diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/i2c/s3c24x0_i2c.c | 85 | ||||
-rw-r--r-- | drivers/i2c/s3c24x0_i2c.h | 7 | ||||
-rw-r--r-- | drivers/mtd/cfi_flash.c | 71 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_ifc_nand.c | 4 | ||||
-rw-r--r-- | drivers/net/phy/mv88e61xx.c | 495 | ||||
-rw-r--r-- | drivers/net/phy/mv88e61xx.h | 39 | ||||
-rw-r--r-- | drivers/power/pmic/pmic_max77686.c | 37 | ||||
-rw-r--r-- | drivers/serial/ns16550.c | 2 | ||||
-rw-r--r-- | drivers/serial/serial_sh.h | 2 | ||||
-rw-r--r-- | drivers/sound/sound.c | 171 | ||||
-rw-r--r-- | drivers/sound/wm8994.c | 74 | ||||
-rw-r--r-- | drivers/sound/wm8994.h | 6 | ||||
-rw-r--r-- | drivers/spi/atmel_spi.c | 2 | ||||
-rw-r--r-- | drivers/spi/exynos_spi.c | 96 | ||||
-rw-r--r-- | drivers/spi/kirkwood_spi.c | 12 | ||||
-rw-r--r-- | drivers/usb/gadget/g_dnl.c | 12 | ||||
-rw-r--r-- | drivers/usb/gadget/pxa25x_udc.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/ehci-exynos.c | 92 | ||||
-rw-r--r-- | drivers/usb/host/ohci-at91.c | 6 | ||||
-rw-r--r-- | drivers/video/exynos_dp.c | 2 | ||||
-rw-r--r-- | drivers/video/exynos_fb.c | 7 | ||||
-rw-r--r-- | drivers/video/exynos_fimd.c | 12 |
23 files changed, 921 insertions, 318 deletions
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 90d297a..769a2ba 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -27,9 +27,11 @@ */ #include <common.h> +#include <fdtdec.h> #if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) #include <asm/arch/clk.h> #include <asm/arch/cpu.h> +#include <asm/arch/pinmux.h> #else #include <asm/arch/s3c24x0_cpu.h> #endif @@ -60,7 +62,16 @@ #define I2C_TIMEOUT 1 /* 1 second */ -static unsigned int g_current_bus; /* Stores Current I2C Bus */ +/* + * For SPL boot some boards need i2c before SDRAM is initialised so force + * variables to live in SRAM + */ +static unsigned int g_current_bus __attribute__((section(".data"))); +#ifdef CONFIG_OF_CONTROL +static int i2c_busses __attribute__((section(".data"))); +static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM] + __attribute__((section(".data"))); +#endif #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) static int GetI2CSDA(void) @@ -512,4 +523,76 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) (i2c, I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, len) != 0); } + +#ifdef CONFIG_OF_CONTROL +void board_i2c_init(const void *blob) +{ + int node_list[CONFIG_MAX_I2C_NUM]; + int count, i; + + count = fdtdec_find_aliases_for_id(blob, "i2c", + COMPAT_SAMSUNG_S3C2440_I2C, node_list, + CONFIG_MAX_I2C_NUM); + + for (i = 0; i < count; i++) { + struct s3c24x0_i2c_bus *bus; + int node = node_list[i]; + + if (node <= 0) + continue; + bus = &i2c_bus[i]; + bus->regs = (struct s3c24x0_i2c *) + fdtdec_get_addr(blob, node, "reg"); + bus->id = pinmux_decode_periph_id(blob, node); + bus->node = node; + bus->bus_num = i2c_busses++; + exynos_pinmux_config(bus->id, 0); + } +} + +static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx) +{ + if (bus_idx < i2c_busses) + return &i2c_bus[bus_idx]; + + debug("Undefined bus: %d\n", bus_idx); + return NULL; +} + +int i2c_get_bus_num_fdt(int node) +{ + int i; + + for (i = 0; i < i2c_busses; i++) { + if (node == i2c_bus[i].node) + return i; + } + + debug("%s: Can't find any matched I2C bus\n", __func__); + return -1; +} + +int i2c_reset_port_fdt(const void *blob, int node) +{ + struct s3c24x0_i2c_bus *i2c; + int bus; + + bus = i2c_get_bus_num_fdt(node); + if (bus < 0) { + debug("could not get bus for node %d\n", node); + return -1; + } + + i2c = get_bus(bus); + if (!i2c) { + debug("get_bus() failed for node node %d\n", node); + return -1; + } + + i2c_ch_init(i2c->regs, CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); + + return 0; +} +#endif + #endif /* CONFIG_HARD_I2C */ diff --git a/drivers/i2c/s3c24x0_i2c.h b/drivers/i2c/s3c24x0_i2c.h index 2dd4b06..a56d749 100644 --- a/drivers/i2c/s3c24x0_i2c.h +++ b/drivers/i2c/s3c24x0_i2c.h @@ -30,4 +30,11 @@ struct s3c24x0_i2c { u32 iicds; u32 iiclc; }; + +struct s3c24x0_i2c_bus { + int node; /* device tree node */ + int bus_num; /* i2c bus number */ + struct s3c24x0_i2c *regs; + int id; +}; #endif /* _S3C24X0_I2C_H */ diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index b2dfc53..60dbb78 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -1128,7 +1128,7 @@ int flash_erase (flash_info_t * info, int s_first, int s_last) AMD_CMD_ERASE_START); flash_unlock_seq (info, sect); flash_write_cmd (info, sect, 0, - AMD_CMD_ERASE_SECTOR); + info->cmd_erase_sector); break; #ifdef CONFIG_FLASH_CFI_LEGACY case CFI_CMDSET_AMD_LEGACY: @@ -1247,6 +1247,8 @@ void flash_print_info (flash_info_t * info) printf(info->chipwidth == FLASH_CFI_16BIT ? "%04X" : "%02X", info->device_id2); } + if ((info->vendor == CFI_CMDSET_AMD_STANDARD) && (info->legacy_unlock)) + printf("\n Advanced Sector Protection (PPB) enabled"); printf ("\n Erase timeout: %ld ms, write timeout: %ld ms\n", info->erase_blk_tout, info->write_tout); @@ -1425,13 +1427,18 @@ int write_buff (flash_info_t * info, uchar * src, ulong addr, ulong cnt) return flash_write_cfiword (info, wp, cword); } +static inline int manufact_match(flash_info_t *info, u32 manu) +{ + return info->manufacturer_id == ((manu & FLASH_VENDMASK) >> 16); +} + /*----------------------------------------------------------------------- */ #ifdef CONFIG_SYS_FLASH_PROTECTION static int cfi_protect_bugfix(flash_info_t *info, long sector, int prot) { - if (info->manufacturer_id == ((INTEL_MANUFACT & FLASH_VENDMASK) >> 16) + if (manufact_match(info, INTEL_MANUFACT) && info->device_id == NUMONYX_256MBIT) { /* * see errata called @@ -1488,8 +1495,7 @@ int flash_real_protect (flash_info_t * info, long sector, int prot) case CFI_CMDSET_AMD_EXTENDED: case CFI_CMDSET_AMD_STANDARD: /* U-Boot only checks the first byte */ - if (info->manufacturer_id == - ((ATM_MANUFACT & FLASH_VENDMASK) >> 16)) { + if (manufact_match(info, ATM_MANUFACT)) { if (prot) { flash_unlock_seq (info, 0); flash_write_cmd (info, 0, @@ -1507,8 +1513,7 @@ int flash_real_protect (flash_info_t * info, long sector, int prot) 0, ATM_CMD_UNLOCK_SECT); } } - if (info->manufacturer_id == - ((AMD_MANUFACT & FLASH_VENDMASK) >> 16)) { + if (info->legacy_unlock) { int flag = disable_interrupts(); int lock_flag; @@ -1733,18 +1738,15 @@ static void cmdset_amd_read_jedec_ids(flash_info_t *info) static int cmdset_amd_init(flash_info_t *info, struct cfi_qry *qry) { info->cmd_reset = AMD_CMD_RESET; + info->cmd_erase_sector = AMD_CMD_ERASE_SECTOR; cmdset_amd_read_jedec_ids(info); flash_write_cmd(info, 0, info->cfi_offset, FLASH_CMD_CFI); #ifdef CONFIG_SYS_FLASH_PROTECTION - if (info->ext_addr && info->manufacturer_id == - ((AMD_MANUFACT & FLASH_VENDMASK) >> 16)) { - ushort spus; - - /* read sector protect/unprotect scheme */ - spus = flash_read_uchar(info, info->ext_addr + 9); - if (spus == 0x8) + if (info->ext_addr) { + /* read sector protect/unprotect scheme (at 0x49) */ + if (flash_read_uchar(info, info->ext_addr + 9) == 0x8) info->legacy_unlock = 1; } #endif @@ -2003,6 +2005,25 @@ static void flash_fixup_stm(flash_info_t *info, struct cfi_qry *qry) } } +static void flash_fixup_sst(flash_info_t *info, struct cfi_qry *qry) +{ + /* + * SST, for many recent nor parallel flashes, says they are + * CFI-conformant. This is not true, since qry struct. + * reports a std. AMD command set (0x0002), while SST allows to + * erase two different sector sizes for the same memory. + * 64KB sector (SST call it block) needs 0x30 to be erased. + * 4KB sector (SST call it sector) needs 0x50 to be erased. + * Since CFI query detect the 4KB number of sectors, users expects + * a sector granularity of 4KB, and it is here set. + */ + if (info->device_id == 0x5D23 || /* SST39VF3201B */ + info->device_id == 0x5C23) { /* SST39VF3202B */ + /* set sector granularity to 4KB */ + info->cmd_erase_sector=0x50; + } +} + /* * The following code cannot be run from FLASH! * @@ -2081,6 +2102,9 @@ ulong flash_get_size (phys_addr_t base, int banknum) case 0x0020: flash_fixup_stm(info, &qry); break; + case 0x00bf: /* SST */ + flash_fixup_sst(info, &qry); + break; } debug ("manufacturer is %d\n", info->vendor); @@ -2158,6 +2182,27 @@ ulong flash_get_size (phys_addr_t base, int banknum) FLASH_OFFSET_PROTECT, FLASH_STATUS_PROTECT); break; + case CFI_CMDSET_AMD_EXTENDED: + case CFI_CMDSET_AMD_STANDARD: + if (!info->legacy_unlock) { + /* default: not protected */ + info->protect[sect_cnt] = 0; + break; + } + + /* Read protection (PPB) from sector */ + flash_write_cmd(info, 0, 0, + info->cmd_reset); + flash_unlock_seq(info, 0); + flash_write_cmd(info, 0, + info->addr_unlock1, + FLASH_CMD_READ_ID); + info->protect[sect_cnt] = + flash_isset( + info, sect_cnt, + FLASH_OFFSET_PROTECT, + FLASH_STATUS_PROTECT); + break; default: /* default: not protected */ info->protect[sect_cnt] = 0; diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 2c3812c..c77c0c4 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -79,6 +79,10 @@ COBJS-$(CONFIG_TEGRA_NAND) += tegra_nand.o COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o +else # minimal SPL drivers + +COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o + endif # drivers endif # nand diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 0878bec..b13d8a9 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -391,7 +391,7 @@ static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, timing = IFC_FIR_OP_RBCD; out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | (timing << IFC_NAND_FIR0_OP2_SHIFT)); out_be32(&ifc->ifc_nand.nand_fcr0, @@ -758,7 +758,7 @@ static void fsl_ifc_sram_init(void) /* READID */ out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | + (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); out_be32(&ifc->ifc_nand.nand_fcr0, diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c index 483a920..e8da66d 100644 --- a/drivers/net/phy/mv88e61xx.c +++ b/drivers/net/phy/mv88e61xx.c @@ -26,6 +26,14 @@ #include <netdev.h> #include "mv88e61xx.h" +/* + * Uncomment either of the following line for local debug control; + * otherwise global debug control will apply. + */ + +/* #undef DEBUG */ +/* #define DEBUG */ + #ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE /* Chip Address mode * The Switch support two modes of operation @@ -52,7 +60,8 @@ static int mv88e61xx_busychk_multic(char *name, u32 devaddr) return 0; } -static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data) +static void mv88e61xx_switch_write(char *name, u32 phy_adr, + u32 reg_ofs, u16 data) { u16 mii_dev_addr; @@ -70,7 +79,8 @@ static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data) 15)); } -static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data) +static void mv88e61xx_switch_read(char *name, u32 phy_adr, + u32 reg_ofs, u16 *data) { u16 mii_dev_addr; @@ -90,110 +100,51 @@ static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data) } #endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ -static void mv88e61xx_port_vlan_config(struct mv88e61xx_config *swconfig, - u32 max_prtnum, u32 ports_ofs) -{ - u32 prt; - u16 reg; - char *name = swconfig->name; - u32 cpu_port = swconfig->cpuport; - u32 port_mask = swconfig->ports_enabled; - enum mv88e61xx_cfg_vlan vlancfg = swconfig->vlancfg; - - /* be sure all ports are disabled */ - for (prt = 0; prt < max_prtnum; prt++) { - RD_PHY(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, ®); - reg &= ~0x3; - WR_PHY(name, ports_ofs + prt, MV88E61XX_PRT_CTRL_REG, reg); - - if (!(cpu_port & (1 << prt))) - continue; - /* Set CPU port VID to 0x1 */ - RD_PHY(name, (ports_ofs + prt), MV88E61XX_PRT_VID_REG, ®); - reg &= ~0xfff; - reg |= 0x1; - WR_PHY(name, (ports_ofs + prt), MV88E61XX_PRT_VID_REG, reg); - } - - /* Setting Port default priority for all ports to zero */ - for (prt = 0; prt < max_prtnum; prt++) { - RD_PHY(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, ®); - reg &= ~0xc000; - WR_PHY(name, ports_ofs + prt, MV88E61XX_PRT_VID_REG, reg); - } - /* Setting VID and VID map for all ports except CPU port */ - for (prt = 0; prt < max_prtnum; prt++) { - /* only for enabled ports */ - if ((1 << prt) & port_mask) { - /* skip CPU port */ - if ((1 << prt) & cpu_port) { - /* - * Set Vlan map table for cpu_port to see - * all ports - */ - RD_PHY(name, (ports_ofs + prt), - MV88E61XX_PRT_VMAP_REG, ®); - reg &= ~((1 << max_prtnum) - 1); - reg |= port_mask & ~(1 << prt); - WR_PHY(name, (ports_ofs + prt), - MV88E61XX_PRT_VMAP_REG, reg); - } else { - - /* - * set Ports VLAN Mapping. - * port prt <--> cpu_port VLAN #prt+1. - */ - RD_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_VID_REG, ®); - reg &= ~0x0fff; - reg |= (prt + 1); - WR_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_VID_REG, reg); - - RD_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_VMAP_REG, ®); - if (vlancfg == MV88E61XX_VLANCFG_DEFAULT) { - /* - * all any port can send frames to all other ports - * ref: sec 3.2.1.1 of datasheet - */ - reg |= 0x03f; - reg &= ~(1 << prt); - } else if (vlancfg == MV88E61XX_VLANCFG_ROUTER) { - /* - * all other ports can send frames to CPU port only - * ref: sec 3.2.1.2 of datasheet - */ - reg &= ~((1 << max_prtnum) - 1); - reg |= cpu_port; - } - WR_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_VMAP_REG, reg); - } - } - } +/* + * Convenience macros for switch device/port reads/writes + * These macros output valid 'mv88e61xx' U_BOOT_CMDs + */ - /* - * enable only appropriate ports to forwarding mode - * and disable the others - */ - for (prt = 0; prt < max_prtnum; prt++) { - if ((1 << prt) & port_mask) { - RD_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_CTRL_REG, ®); - reg |= 0x3; - WR_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_CTRL_REG, reg); - } else { - /* Disable port */ - RD_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_CTRL_REG, ®); - reg &= ~0x3; - WR_PHY(name, ports_ofs + prt, - MV88E61XX_PRT_CTRL_REG, reg); - } - } +#ifndef DEBUG +#define WR_SWITCH_REG wr_switch_reg +#define RD_SWITCH_REG rd_switch_reg +#define WR_SWITCH_PORT_REG(n, p, r, d) \ + WR_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d) +#define RD_SWITCH_PORT_REG(n, p, r, d) \ + RD_SWITCH_REG(n, (MV88E61XX_PRT_OFST+p), r, d) +#else +static void WR_SWITCH_REG(char *name, u32 dev_adr, u32 reg_ofs, u16 data) +{ + printf("mv88e61xx %s dev %02x reg %02x write %04x\n", + name, dev_adr, reg_ofs, data); + wr_switch_reg(name, dev_adr, reg_ofs, data); } +static void RD_SWITCH_REG(char *name, u32 dev_adr, u32 reg_ofs, u16 *data) +{ + rd_switch_reg(name, dev_adr, reg_ofs, data); + printf("mv88e61xx %s dev %02x reg %02x read %04x\n", + name, dev_adr, reg_ofs, *data); +} +static void WR_SWITCH_PORT_REG(char *name, u32 prt_adr, u32 reg_ofs, + u16 data) +{ + printf("mv88e61xx %s port %02x reg %02x write %04x\n", + name, prt_adr, reg_ofs, data); + wr_switch_reg(name, (MV88E61XX_PRT_OFST+prt_adr), reg_ofs, data); +} +static void RD_SWITCH_PORT_REG(char *name, u32 prt_adr, u32 reg_ofs, + u16 *data) +{ + rd_switch_reg(name, (MV88E61XX_PRT_OFST+prt_adr), reg_ofs, data); + printf("mv88e61xx %s port %02x reg %02x read %04x\n", + name, prt_adr, reg_ofs, *data); +} +#endif + +/* + * Local functions to read/write registers on the switch PHYs. + * NOTE! This goes through switch, not direct miiphy, writes and reads! + */ /* * Make sure SMIBusy bit cleared before another @@ -204,7 +155,7 @@ static int mv88e61xx_busychk(char *name) u16 reg = 0; u32 timeout = MV88E61XX_PHY_TIMEOUT; do { - RD_PHY(name, MV88E61XX_GLB2REG_DEVADR, + rd_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD, ®); if (timeout-- == 0) { printf("SMI busy timeout\n"); @@ -214,34 +165,110 @@ static int mv88e61xx_busychk(char *name) return 0; } +static inline int mv88e61xx_switch_miiphy_write(char *name, u32 phy, + u32 reg, u16 data) +{ + /* write switch data reg then cmd reg then check completion */ + wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, + data); + wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD, + (MV88E61XX_PHY_WRITE_CMD | (phy << 5) | reg)); + return mv88e61xx_busychk(name); +} + +static inline int mv88e61xx_switch_miiphy_read(char *name, u32 phy, + u32 reg, u16 *data) +{ + /* write switch cmd reg, check for completion */ + wr_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_CMD, + (MV88E61XX_PHY_READ_CMD | (phy << 5) | reg)); + if (mv88e61xx_busychk(name)) + return -1; + /* read switch data reg and return success */ + rd_switch_reg(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, data); + return 0; +} + +/* + * Convenience macros for switch PHY reads/writes + */ + +#ifndef DEBUG +#define WR_SWITCH_PHY_REG mv88e61xx_switch_miiphy_write +#define RD_SWITCH_PHY_REG mv88e61xx_switch_miiphy_read +#else +static inline int WR_SWITCH_PHY_REG(char *name, u32 phy_adr, + u32 reg_ofs, u16 data) +{ + int r = mv88e61xx_switch_miiphy_write(name, phy_adr, reg_ofs, data); + if (r) + printf("** ERROR writing mv88e61xx %s phy %02x reg %02x\n", + name, phy_adr, reg_ofs); + else + printf("mv88e61xx %s phy %02x reg %02x write %04x\n", + name, phy_adr, reg_ofs, data); + return r; +} +static inline int RD_SWITCH_PHY_REG(char *name, u32 phy_adr, + u32 reg_ofs, u16 *data) +{ + int r = mv88e61xx_switch_miiphy_read(name, phy_adr, reg_ofs, data); + if (r) + printf("** ERROR reading mv88e61xx %s phy %02x reg %02x\n", + name, phy_adr, reg_ofs); + else + printf("mv88e61xx %s phy %02x reg %02x read %04x\n", + name, phy_adr, reg_ofs, *data); + return r; +} +#endif + +static void mv88e61xx_port_vlan_config(struct mv88e61xx_config *swconfig) +{ + u32 prt; + u16 reg; + char *name = swconfig->name; + u32 port_mask = swconfig->ports_enabled; + + /* apply internal vlan config */ + for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { + /* only for enabled ports */ + if ((1 << prt) & port_mask) { + /* take vlan map from swconfig */ + u8 vlanmap = swconfig->vlancfg[prt]; + /* remove disabled ports from vlan map */ + vlanmap &= swconfig->ports_enabled; + /* apply vlan map to port */ + RD_SWITCH_PORT_REG(name, prt, + MV88E61XX_PRT_VMAP_REG, ®); + reg &= ~((1 << MV88E61XX_MAX_PORTS_NUM) - 1); + reg |= vlanmap; + WR_SWITCH_PORT_REG(name, prt, + MV88E61XX_PRT_VMAP_REG, reg); + } + } +} + /* * Power up the specified port and reset PHY */ -static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 prt) +static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 phy) { char *name = swconfig->name; - /* Write Copper Specific control reg1 (0x14) for- + /* Write Copper Specific control reg1 (0x10) for- * Enable Phy power up * Energy Detect on (sense&Xmit NLP Periodically * reset other settings default */ - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, 0x3360); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (0x9410 | (prt << 5))); - - if (mv88e61xx_busychk(name)) + if (WR_SWITCH_PHY_REG(name, phy, 0x10, 0x3360)) return -1; /* Write PHY ctrl reg (0x0) to apply * Phy reset (set bit 15 low) * reset other default values */ - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, 0x1140); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (0x9400 | (prt << 5))); - - if (mv88e61xx_busychk(name)) + if (WR_SWITCH_PHY_REG(name, phy, 0x00, 0x9140)) return -1; return 0; @@ -256,48 +283,26 @@ static int mv88361xx_powerup(struct mv88e61xx_config *swconfig, u32 prt) * to setup PHY LEDs default configuration to detect 10/100/1000Mb/s * Link status */ -static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 prt) +static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 phy) { char *name = swconfig->name; - u16 reg; if (swconfig->led_init != MV88E61XX_LED_INIT_EN) return 0; /* set page address to 3 */ - reg = 3; - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | - 1 << MV88E61XX_MODE_OFST | - 1 << MV88E61XX_OP_OFST | - prt << MV88E61XX_ADDR_OFST | 22)); - - if (mv88e61xx_busychk(name)) + if (WR_SWITCH_PHY_REG(name, phy, 0x16, 0x0003)) return -1; - /* set LED Func Ctrl reg */ - reg = 1; /* LED[0] On-Link, Blink-Activity, Off-NoLink */ - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | - 1 << MV88E61XX_MODE_OFST | - 1 << MV88E61XX_OP_OFST | - prt << MV88E61XX_ADDR_OFST | 16)); - - if (mv88e61xx_busychk(name)) + /* + * set LED Func Ctrl reg + * value 0x0001 = LED[0] On-Link, Blink-Activity, Off-NoLink + */ + if (WR_SWITCH_PHY_REG(name, phy, 0x10, 0x0001)) return -1; /* set page address to 0 */ - reg = 0; - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | - 1 << MV88E61XX_MODE_OFST | - 1 << MV88E61XX_OP_OFST | - prt << MV88E61XX_ADDR_OFST | 22)); - - if (mv88e61xx_busychk(name)) + if (WR_SWITCH_PHY_REG(name, phy, 0x16, 0x0000)) return -1; return 0; @@ -312,23 +317,15 @@ static int mv88361xx_led_init(struct mv88e61xx_config *swconfig, u32 prt) * This is optional settings may be needed on some boards * for PHY<->magnetics h/w tuning */ -static int mv88361xx_reverse_mdipn(struct mv88e61xx_config *swconfig, u32 prt) +static int mv88361xx_reverse_mdipn(struct mv88e61xx_config *swconfig, u32 phy) { char *name = swconfig->name; - u16 reg; if (swconfig->mdip != MV88E61XX_MDIP_REVERSE) return 0; - reg = 0x0f; /*Reverse MDIP/N[3:0] bits */ - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, MV88E61XX_PHY_DATA, reg); - WR_PHY(name, MV88E61XX_GLB2REG_DEVADR, - MV88E61XX_PHY_CMD, (1 << MV88E61XX_BUSY_OFST | - 1 << MV88E61XX_MODE_OFST | - 1 << MV88E61XX_OP_OFST | - prt << MV88E61XX_ADDR_OFST | 20)); - - if (mv88e61xx_busychk(name)) + /*Reverse MDIP/N[3:0] bits */ + if (WR_SWITCH_PHY_REG(name, phy, 0x14, 0x000f)) return -1; return 0; @@ -343,6 +340,7 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig) u16 reg; char *idstr; char *name = swconfig->name; + int time; if (miiphy_set_current_dev(name)) { printf("%s failed\n", __FUNCTION__); @@ -354,7 +352,7 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig) printf("Invalid cpu port config, using default port5\n"); } - RD_PHY(name, MV88E61XX_PRT_OFST, MII_PHYSID2, ®); + RD_SWITCH_PORT_REG(name, 0, MII_PHYSID2, ®); switch (reg &= 0xfff0) { case 0x1610: idstr = "88E6161"; @@ -373,46 +371,183 @@ int mv88e61xx_switch_initialize(struct mv88e61xx_config *swconfig) break; } - /* Port based VLANs configuration */ - if ((swconfig->vlancfg == MV88E61XX_VLANCFG_DEFAULT) - || (swconfig->vlancfg == MV88E61XX_VLANCFG_ROUTER)) - mv88e61xx_port_vlan_config(swconfig, MV88E61XX_MAX_PORTS_NUM, - MV88E61XX_PRT_OFST); - else { - printf("Unsupported mode %s failed\n", __FUNCTION__); - return -1; + /* be sure all ports are disabled */ + for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { + RD_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, ®); + reg &= ~0x3; + WR_SWITCH_PORT_REG(name, prt, MV88E61XX_PRT_CTRL_REG, reg); } + /* wait 2 ms for queues to drain */ + udelay(2000); + + /* reset switch */ + RD_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGCR, ®); + reg |= 0x8000; + WR_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGCR, reg); + + /* wait up to 1 second for switch reset complete */ + for (time = 1000; time; time--) { + RD_SWITCH_REG(name, MV88E61XX_GLBREG_DEVADR, MV88E61XX_SGSR, + ®); + if ((reg & 0xc800) == 0xc800) + break; + udelay(1000); + } + if (!time) + return -1; + + /* Port based VLANs configuration */ + mv88e61xx_port_vlan_config(swconfig); + if (swconfig->rgmii_delay == MV88E61XX_RGMII_DELAY_EN) { /* * Enable RGMII delay on Tx and Rx for CPU port * Ref: sec 9.5 of chip datasheet-02 */ - WR_PHY(name, MV88E61XX_PRT_OFST + 5, - MV88E61XX_RGMII_TIMECTRL_REG, 0x18); - WR_PHY(name, MV88E61XX_PRT_OFST + 4, - MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7); + /*Force port link down */ + WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x10); + /* configure port RGMII delay */ + WR_SWITCH_PORT_REG(name, 4, + MV88E61XX_RGMII_TIMECTRL_REG, 0x81e7); + RD_SWITCH_PORT_REG(name, 5, + MV88E61XX_RGMII_TIMECTRL_REG, ®); + WR_SWITCH_PORT_REG(name, 5, + MV88E61XX_RGMII_TIMECTRL_REG, reg | 0x18); + WR_SWITCH_PORT_REG(name, 4, + MV88E61XX_RGMII_TIMECTRL_REG, 0xc1e7); + /* Force port to RGMII FDX 1000Base then up */ + WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x1e); + WR_SWITCH_PORT_REG(name, 5, MV88E61XX_PCS_CTRL_REG, 0x3e); } for (prt = 0; prt < MV88E61XX_MAX_PORTS_NUM; prt++) { - if (!((1 << prt) & swconfig->cpuport)) { - if (mv88361xx_led_init(swconfig, prt)) + /* configure port's PHY */ + if (!((1 << prt) & swconfig->cpuport)) { + /* port 4 has phy 6, not 4 */ + int phy = (prt == 4) ? 6 : prt; + if (mv88361xx_powerup(swconfig, phy)) return -1; - if (mv88361xx_reverse_mdipn(swconfig, prt)) + if (mv88361xx_reverse_mdipn(swconfig, phy)) return -1; - if (mv88361xx_powerup(swconfig, prt)) + if (mv88361xx_led_init(swconfig, phy)) return -1; } + /* set port VID to port+1 except for cpu port */ + if (!((1 << prt) & swconfig->cpuport)) { + RD_SWITCH_PORT_REG(name, prt, + MV88E61XX_PRT_VID_REG, ®); + WR_SWITCH_PORT_REG(name, prt, + MV88E61XX_PRT_VID_REG, + (reg & ~1023) | (prt+1)); + } + /*Program port state */ - RD_PHY(name, MV88E61XX_PRT_OFST + prt, - MV88E61XX_PRT_CTRL_REG, ®); - WR_PHY(name, MV88E61XX_PRT_OFST + prt, - MV88E61XX_PRT_CTRL_REG, - reg | (swconfig->portstate & 0x03)); + RD_SWITCH_PORT_REG(name, prt, + MV88E61XX_PRT_CTRL_REG, ®); + WR_SWITCH_PORT_REG(name, prt, + MV88E61XX_PRT_CTRL_REG, + reg | (swconfig->portstate & 0x03)); + } printf("%s Initialized on %s\n", idstr, name); return 0; } + +#ifdef CONFIG_MV88E61XX_CMD +static int +do_switch(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char *name, *endp; + int write = 0; + enum { dev, prt, phy } target = dev; + u32 addrlo, addrhi, addr; + u32 reglo, reghi, reg; + u16 data, rdata; + + if (argc < 7) + return -1; + + name = argv[1]; + + if (strcmp(argv[2], "phy") == 0) + target = phy; + else if (strcmp(argv[2], "port") == 0) + target = prt; + else if (strcmp(argv[2], "dev") != 0) + return 1; + + addrlo = simple_strtoul(argv[3], &endp, 16); + + if (!*endp) { + addrhi = addrlo; + } else { + while (*endp < '0' || *endp > '9') + endp++; + addrhi = simple_strtoul(endp, NULL, 16); + } + + reglo = simple_strtoul(argv[5], &endp, 16); + if (!*endp) { + reghi = reglo; + } else { + while (*endp < '0' || *endp > '9') + endp++; + reghi = simple_strtoul(endp, NULL, 16); + } + + if (strcmp(argv[6], "write") == 0) + write = 1; + else if (strcmp(argv[6], "read") != 0) + return 1; + + data = simple_strtoul(argv[7], NULL, 16); + + for (addr = addrlo; addr <= addrhi; addr++) { + for (reg = reglo; reg <= reghi; reg++) { + if (write) { + if (target == phy) + mv88e61xx_switch_miiphy_write( + name, addr, reg, data); + else if (target == prt) + wr_switch_reg(name, + addr+MV88E61XX_PRT_OFST, + reg, data); + else + wr_switch_reg(name, addr, reg, data); + } else { + if (target == phy) + mv88e61xx_switch_miiphy_read( + name, addr, reg, &rdata); + else if (target == prt) + rd_switch_reg(name, + addr+MV88E61XX_PRT_OFST, + reg, &rdata); + else + rd_switch_reg(name, addr, reg, &rdata); + printf("%s %s %s %02x %s %02x %s %04x\n", + argv[0], argv[1], argv[2], addr, + argv[4], reg, argv[6], rdata); + if (write && argc == 7 && rdata != data) + return 1; + } + } + } + return 0; +} + +U_BOOT_CMD(mv88e61xx, 8, 0, do_switch, + "Read or write mv88e61xx switch registers", + "<ethdevice> dev|port|phy <addr> reg <reg> write <data>\n" + "<ethdevice> dev|port|phy <addr> reg <reg> read [<data>]\n" + " - read/write switch device, port or phy at (addr,reg)\n" + " addr=0..0x1C for dev, 0..5 for port or phy.\n" + " reg=0..0x1F.\n" + " data=0..0xFFFF (tested if present against actual read).\n" + " All numeric parameters are assumed to be hex.\n" + " <addr> and <<reg> arguments can be ranges (x..y)" +); +#endif /* CONFIG_MV88E61XX_CMD */ diff --git a/drivers/net/phy/mv88e61xx.h b/drivers/net/phy/mv88e61xx.h index 57762b6..55ded7e 100644 --- a/drivers/net/phy/mv88e61xx.h +++ b/drivers/net/phy/mv88e61xx.h @@ -28,35 +28,50 @@ #include <miiphy.h> #define MV88E61XX_CPU_PORT 0x5 -#define MV88E61XX_MAX_PORTS_NUM 0x6 #define MV88E61XX_PHY_TIMEOUT 100000 -#define MV88E61XX_PRT_STS_REG 0x1 +/* port dev-addr (= port + 0x10) */ +#define MV88E61XX_PRT_OFST 0x10 +/* port registers */ +#define MV88E61XX_PCS_CTRL_REG 0x1 #define MV88E61XX_PRT_CTRL_REG 0x4 #define MV88E61XX_PRT_VMAP_REG 0x6 #define MV88E61XX_PRT_VID_REG 0x7 +#define MV88E61XX_RGMII_TIMECTRL_REG 0x1A -#define MV88E61XX_PRT_OFST 0x10 +/* global registers dev-addr */ +#define MV88E61XX_GLBREG_DEVADR 0x1B +/* global registers */ +#define MV88E61XX_SGSR 0x00 +#define MV88E61XX_SGCR 0x04 + +/* global 2 registers dev-addr */ +#define MV88E61XX_GLB2REG_DEVADR 0x1C +/* global 2 registers */ #define MV88E61XX_PHY_CMD 0x18 #define MV88E61XX_PHY_DATA 0x19 -#define MV88E61XX_RGMII_TIMECTRL_REG 0x1A -#define MV88E61XX_GLB2REG_DEVADR 0x1C +/* global 2 phy commands */ +#define MV88E61XX_PHY_WRITE_CMD 0x9400 +#define MV88E61XX_PHY_READ_CMD 0x9800 #define MV88E61XX_BUSY_OFST 15 #define MV88E61XX_MODE_OFST 12 -#define MV88E61XX_OP_OFST 10 +#define MV88E61XX_OP_OFST 10 #define MV88E61XX_ADDR_OFST 5 #ifdef CONFIG_MV88E61XX_MULTICHIP_ADRMODE static int mv88e61xx_busychk_multic(char *name, u32 devaddr); -static void mv88e61xx_wr_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 data); -static void mv88e61xx_rd_phy(char *name, u32 phy_adr, u32 reg_ofs, u16 * data); -#define WR_PHY mv88e61xx_wr_phy -#define RD_PHY mv88e61xx_rd_phy +static void mv88e61xx_switch_write(char *name, u32 phy_adr, + u32 reg_ofs, u16 data); +static void mv88e61xx_switch_read(char *name, u32 phy_adr, + u32 reg_ofs, u16 *data); +#define wr_switch_reg mv88e61xx_switch_write +#define rd_switch_reg mv88e61xx_switch_read #else -#define WR_PHY miiphy_write -#define RD_PHY miiphy_read +/* switch appears a s simple PHY and can thus use miiphy */ +#define wr_switch_reg miiphy_write +#define rd_switch_reg miiphy_read #endif /* CONFIG_MV88E61XX_MULTICHIP_ADRMODE */ #endif /* _MV88E61XX_H */ diff --git a/drivers/power/pmic/pmic_max77686.c b/drivers/power/pmic/pmic_max77686.c index fce0183..7fcb4c0 100644 --- a/drivers/power/pmic/pmic_max77686.c +++ b/drivers/power/pmic/pmic_max77686.c @@ -22,10 +22,14 @@ */ #include <common.h> +#include <fdtdec.h> +#include <i2c.h> #include <power/pmic.h> #include <power/max77686_pmic.h> #include <errno.h> +DECLARE_GLOBAL_DATA_PTR; + int pmic_init(unsigned char bus) { static const char name[] = "MAX77686_PMIC"; @@ -36,13 +40,40 @@ int pmic_init(unsigned char bus) return -ENOMEM; } - puts("Board PMIC init\n"); +#ifdef CONFIG_OF_CONTROL + const void *blob = gd->fdt_blob; + int node, parent; + + node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_MAX77686_PMIC); + if (node < 0) { + debug("PMIC: No node for PMIC Chip in device tree\n"); + debug("node = %d\n", node); + return -1; + } + + parent = fdt_parent_offset(blob, node); + if (parent < 0) { + debug("%s: Cannot find node parent\n", __func__); + return -1; + } + + p->bus = i2c_get_bus_num_fdt(parent); + if (p->bus < 0) { + debug("%s: Cannot find I2C bus\n", __func__); + return -1; + } + p->hw.i2c.addr = fdtdec_get_int(blob, node, "reg", 9); +#else + p->bus = bus; + p->hw.i2c.addr = MAX77686_I2C_ADDR; +#endif + p->name = name; p->interface = PMIC_I2C; p->number_of_regs = PMIC_NUM_OF_REGS; - p->hw.i2c.addr = MAX77686_I2C_ADDR; p->hw.i2c.tx_num = 1; - p->bus = bus; + + puts("Board PMIC init\n"); return 0; } diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index bbd91ca..87a0917 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -36,8 +36,10 @@ void NS16550_init(NS16550_t com_port, int baud_divisor) { +#if (!defined(CONFIG_SYS_NS16550_BROKEN_TEMT)) while (!(serial_in(&com_port->lsr) & UART_LSR_TEMT)) ; +#endif serial_out(CONFIG_SYS_NS16550_IER, &com_port->ier); #if (defined(CONFIG_OMAP) && !defined(CONFIG_OMAP3_ZOOM2)) || \ diff --git a/drivers/serial/serial_sh.h b/drivers/serial/serial_sh.h index a33334e..7e38a3f 100644 --- a/drivers/serial/serial_sh.h +++ b/drivers/serial/serial_sh.h @@ -143,7 +143,7 @@ struct uart_port { #elif defined(CONFIG_H8S2678) # define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */ # define H8300_SCI_DR(ch) (*(volatile char *)(P1DR + h8300_sci_pins[ch].port)) -#elif defined(CONFIG_CPU_SH7757) +#elif defined(CONFIG_CPU_SH7757) || defined(CONFIG_CPU_SH7752) # define SCSPTR0 0xfe4b0020 # define SCSPTR1 0xfe4b0020 # define SCSPTR2 0xfe4b0020 diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c index 4c74534..fa8432d 100644 --- a/drivers/sound/sound.c +++ b/drivers/sound/sound.c @@ -24,111 +24,159 @@ #include <malloc.h> #include <common.h> #include <asm/io.h> +#include <libfdt.h> +#include <fdtdec.h> #include <i2c.h> #include <i2s.h> #include <sound.h> -#include "wm8994.h" #include <asm/arch/sound.h> +#include "wm8994.h" /* defines */ #define SOUND_400_HZ 400 #define SOUND_BITS_IN_BYTE 8 static struct i2stx_info g_i2stx_pri; -static struct sound_codec_info g_codec_info; /* - * get_sound_fdt_values gets fdt values for i2s parameters + * get_sound_i2s_values gets values for i2s parameters * * @param i2stx_info i2s transmitter transfer param structure - * @param blob FDT blob - */ -static void get_sound_i2s_values(struct i2stx_info *i2s) -{ - i2s->base_address = samsung_get_base_i2s(); - i2s->audio_pll_clk = I2S_PLL_CLK; - i2s->samplingrate = I2S_SAMPLING_RATE; - i2s->bitspersample = I2S_BITS_PER_SAMPLE; - i2s->channels = I2S_CHANNELS; - i2s->rfs = I2S_RFS; - i2s->bfs = I2S_BFS; -} - -/* - * Gets fdt values for wm8994 config parameters - * - * @param pcodec_info codec information structure - * @param blob FDT blob - * @return int value, 0 for success + * @param blob FDT blob if enabled else NULL */ -static int get_sound_wm8994_values(struct sound_codec_info *pcodec_info) +static int get_sound_i2s_values(struct i2stx_info *i2s, const void *blob) { +#ifdef CONFIG_OF_CONTROL + int node; int error = 0; + int base; - switch (AUDIO_COMPAT) { - case AUDIO_COMPAT_SPI: - debug("%s: Support not added for SPI interface\n", __func__); + node = fdtdec_next_compatible(blob, 0, + COMPAT_SAMSUNG_EXYNOS5_SOUND); + if (node <= 0) { + debug("EXYNOS_SOUND: No node for sound in device tree\n"); return -1; - break; - case AUDIO_COMPAT_I2C: - pcodec_info->i2c_bus = AUDIO_I2C_BUS; - pcodec_info->i2c_dev_addr = AUDIO_I2C_REG; - debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr); - break; - default: - debug("%s: Unknown compat id %d\n", __func__, AUDIO_COMPAT); + } + + /* + * Get the pre-defined sound specific values from FDT. + * All of these are expected to be correct otherwise + * wrong register values in i2s setup parameters + * may result in no sound play. + */ + base = fdtdec_get_addr(blob, node, "reg"); + if (base == FDT_ADDR_T_NONE) { + debug("%s: Missing i2s base\n", __func__); return -1; } + i2s->base_address = base; + i2s->audio_pll_clk = fdtdec_get_int(blob, + node, "samsung,i2s-epll-clock-frequency", -1); + error |= i2s->audio_pll_clk; + debug("audio_pll_clk = %d\n", i2s->audio_pll_clk); + i2s->samplingrate = fdtdec_get_int(blob, + node, "samsung,i2s-sampling-rate", -1); + error |= i2s->samplingrate; + debug("samplingrate = %d\n", i2s->samplingrate); + i2s->bitspersample = fdtdec_get_int(blob, + node, "samsung,i2s-bits-per-sample", -1); + error |= i2s->bitspersample; + debug("bitspersample = %d\n", i2s->bitspersample); + i2s->channels = fdtdec_get_int(blob, + node, "samsung,i2s-channels", -1); + error |= i2s->channels; + debug("channels = %d\n", i2s->channels); + i2s->rfs = fdtdec_get_int(blob, + node, "samsung,i2s-lr-clk-framesize", -1); + error |= i2s->rfs; + debug("rfs = %d\n", i2s->rfs); + i2s->bfs = fdtdec_get_int(blob, + node, "samsung,i2s-bit-clk-framesize", -1); + error |= i2s->bfs; + debug("bfs = %d\n", i2s->bfs); if (error == -1) { - debug("fail to get wm8994 codec node properties\n"); + debug("fail to get sound i2s node properties\n"); return -1; } - +#else + i2s->base_address = samsung_get_base_i2s(); + i2s->audio_pll_clk = I2S_PLL_CLK; + i2s->samplingrate = I2S_SAMPLING_RATE; + i2s->bitspersample = I2S_BITS_PER_SAMPLE; + i2s->channels = I2S_CHANNELS; + i2s->rfs = I2S_RFS; + i2s->bfs = I2S_BFS; +#endif return 0; } /* - * Gets fdt values for codec config parameters + * Init codec * - * @param pcodec_info codec information structure - * @param blob FDT blob - * @return int value, 0 for success + * @param blob FDT blob + * @param pi2s_tx i2s parameters required by codec + * @return int value, 0 for success */ -static int get_sound_codec_values(struct sound_codec_info *pcodec_info) +static int codec_init(const void *blob, struct i2stx_info *pi2s_tx) { - int error = 0; + int ret; const char *codectype; +#ifdef CONFIG_OF_CONTROL + int node; - codectype = AUDIO_CODEC; + /* Get the node from FDT for sound */ + node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_SOUND); + if (node <= 0) { + debug("EXYNOS_SOUND: No node for sound in device tree\n"); + debug("node = %d\n", node); + return -1; + } + /* + * Get the pre-defined sound codec specific values from FDT. + * All of these are expected to be correct otherwise sound + * can not be played + */ + codectype = fdt_getprop(blob, node, "samsung,codec-type", NULL); + debug("device = %s\n", codectype); +#else + codectype = AUDIO_CODEC; +#endif if (!strcmp(codectype, "wm8994")) { - pcodec_info->codec_type = CODEC_WM_8994; - error = get_sound_wm8994_values(pcodec_info); + /* Check the codec type and initialise the same */ + ret = wm8994_init(blob, WM8994_AIF2, + pi2s_tx->samplingrate, + (pi2s_tx->samplingrate * (pi2s_tx->rfs)), + pi2s_tx->bitspersample, pi2s_tx->channels); } else { - error = -1; + debug("%s: Unknown code type %s\n", __func__, + codectype); + return -1; } - - if (error == -1) { - debug("fail to get sound codec node properties\n"); + if (ret) { + debug("%s: Codec init failed\n", __func__); return -1; } return 0; } -int sound_init(void) +int sound_init(const void *blob) { int ret; struct i2stx_info *pi2s_tx = &g_i2stx_pri; - struct sound_codec_info *pcodec_info = &g_codec_info; /* Get the I2S Values */ - get_sound_i2s_values(pi2s_tx); + if (get_sound_i2s_values(pi2s_tx, blob) < 0) { + debug(" FDT I2S values failed\n"); + return -1; + } - /* Get the codec Values */ - if (get_sound_codec_values(pcodec_info) < 0) + if (codec_init(blob, pi2s_tx) < 0) { + debug(" Codec init failed\n"); return -1; + } ret = i2s_tx_init(pi2s_tx); if (ret) { @@ -137,21 +185,6 @@ int sound_init(void) return ret; } - /* Check the codec type and initialise the same */ - if (pcodec_info->codec_type == CODEC_WM_8994) { - ret = wm8994_init(pcodec_info, WM8994_AIF2, - pi2s_tx->samplingrate, - (pi2s_tx->samplingrate * (pi2s_tx->rfs)), - pi2s_tx->bitspersample, pi2s_tx->channels); - } else { - debug("%s: Unknown code type %d\n", __func__, - pcodec_info->codec_type); - return -1; - } - if (ret) { - debug("%s: Codec init failed\n", __func__); - return -1; - } return ret; } diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c index 293903a..3b673b4 100644 --- a/drivers/sound/wm8994.c +++ b/drivers/sound/wm8994.c @@ -26,9 +26,11 @@ #include <asm/io.h> #include <common.h> #include <div64.h> +#include <fdtdec.h> #include <i2c.h> #include <i2s.h> #include <sound.h> +#include <asm/arch/sound.h> #include "wm8994.h" #include "wm8994_registers.h" @@ -77,6 +79,7 @@ static int bclk_divs[] = { static struct wm8994_priv g_wm8994_info; static unsigned char g_wm8994_i2c_dev_addr; +static struct sound_codec_info g_codec_info; /* * Initialise I2C for wm 8994 @@ -747,13 +750,80 @@ err: return -1; } +/* + * Gets fdt values for wm8994 config parameters + * + * @param pcodec_info codec information structure + * @param blob FDT blob + * @return int value, 0 for success + */ +static int get_codec_values(struct sound_codec_info *pcodec_info, + const void *blob) +{ + int error = 0; +#ifdef CONFIG_OF_CONTROL + enum fdt_compat_id compat; + int node; + int parent; + + /* Get the node from FDT for codec */ + node = fdtdec_next_compatible(blob, 0, COMPAT_WOLFSON_WM8994_CODEC); + if (node <= 0) { + debug("EXYNOS_SOUND: No node for codec in device tree\n"); + debug("node = %d\n", node); + return -1; + } + + parent = fdt_parent_offset(blob, node); + if (parent < 0) { + debug("%s: Cannot find node parent\n", __func__); + return -1; + } + + compat = fdtdec_lookup(blob, parent); + switch (compat) { + case COMPAT_SAMSUNG_S3C2440_I2C: + pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent); + error |= pcodec_info->i2c_bus; + debug("i2c bus = %d\n", pcodec_info->i2c_bus); + pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node, + "reg", 0); + error |= pcodec_info->i2c_dev_addr; + debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr); + break; + default: + debug("%s: Unknown compat id %d\n", __func__, compat); + return -1; + } +#else + pcodec_info->i2c_bus = AUDIO_I2C_BUS; + pcodec_info->i2c_dev_addr = AUDIO_I2C_REG; + debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr); +#endif + + pcodec_info->codec_type = CODEC_WM_8994; + + if (error == -1) { + debug("fail to get wm8994 codec node properties\n"); + return -1; + } + + return 0; +} + /*wm8994 Device Initialisation */ -int wm8994_init(struct sound_codec_info *pcodec_info, - enum en_audio_interface aif_id, +int wm8994_init(const void *blob, enum en_audio_interface aif_id, int sampling_rate, int mclk_freq, int bits_per_sample, unsigned int channels) { int ret = 0; + struct sound_codec_info *pcodec_info = &g_codec_info; + + /* Get the codec Values */ + if (get_codec_values(pcodec_info, blob) < 0) { + debug("FDT Codec values failed\n"); + return -1; + } /* shift the device address by 1 for 7 bit addressing */ g_wm8994_i2c_dev_addr = pcodec_info->i2c_dev_addr; diff --git a/drivers/sound/wm8994.h b/drivers/sound/wm8994.h index a8f0de1..a1e8335 100644 --- a/drivers/sound/wm8994.h +++ b/drivers/sound/wm8994.h @@ -69,8 +69,7 @@ enum wm8994_type { /* * intialise wm8994 sound codec device for the given configuration * - * @param pcodec_info pointer value of the sound codec info structure - * parsed from device tree + * @param blob FDT node for codec values * @param aif_id enum value of codec interface port in which * soc i2s is connected * @param sampling_rate Sampling rate ranges between from 8khz to 96khz @@ -80,8 +79,7 @@ enum wm8994_type { * * @returns -1 for error and 0 Success. */ -int wm8994_init(struct sound_codec_info *pcodec_info, - enum en_audio_interface aif_id, +int wm8994_init(const void *blob, enum en_audio_interface aif_id, int sampling_rate, int mclk_freq, int bits_per_sample, unsigned int channels); #endif /*__WM8994_H__ */ diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index c7a51f7..ce7d460 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -92,7 +92,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, as->slave.cs = cs; as->regs = regs; as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS -#if defined(CONFIG_AT91SAM9X5) +#if defined(CONFIG_AT91SAM9X5) || defined(CONFIG_AT91SAM9M10G45) | ATMEL_SPI_MR_WDRBT #endif | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf); diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index 3e6c18f..be60ada 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -20,6 +20,7 @@ #include <common.h> #include <malloc.h> #include <spi.h> +#include <fdtdec.h> #include <asm/arch/clk.h> #include <asm/arch/clock.h> #include <asm/arch/cpu.h> @@ -28,16 +29,20 @@ #include <asm/arch-exynos/spi.h> #include <asm/io.h> +DECLARE_GLOBAL_DATA_PTR; + /* Information about each SPI controller */ struct spi_bus { enum periph_id periph_id; s32 frequency; /* Default clock frequency, -1 for none */ struct exynos_spi *regs; int inited; /* 1 if this bus is ready for use */ + int node; }; /* A list of spi buses that we know about */ static struct spi_bus spi_bus[EXYNOS5_SPI_NUM_CONTROLLERS]; +static unsigned int bus_count; struct exynos_spi_slave { struct spi_slave slave; @@ -50,7 +55,7 @@ struct exynos_spi_slave { static struct spi_bus *spi_get_bus(unsigned dev_index) { - if (dev_index < EXYNOS5_SPI_NUM_CONTROLLERS) + if (dev_index < bus_count) return &spi_bus[dev_index]; debug("%s: invalid bus %d", __func__, dev_index); @@ -347,21 +352,100 @@ static inline struct exynos_spi *get_spi_base(int dev_index) (dev_index - 3); } +/* + * Read the SPI config from the device tree node. + * + * @param blob FDT blob to read from + * @param node Node offset to read from + * @param bus SPI bus structure to fill with information + * @return 0 if ok, or -FDT_ERR_NOTFOUND if something was missing + */ +static int spi_get_config(const void *blob, int node, struct spi_bus *bus) +{ + bus->node = node; + bus->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg"); + bus->periph_id = pinmux_decode_periph_id(blob, node); + + if (bus->periph_id == PERIPH_ID_NONE) { + debug("%s: Invalid peripheral ID %d\n", __func__, + bus->periph_id); + return -FDT_ERR_NOTFOUND; + } + + /* Use 500KHz as a suitable default */ + bus->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", + 500000); + + return 0; +} + +/* + * Process a list of nodes, adding them to our list of SPI ports. + * + * @param blob fdt blob + * @param node_list list of nodes to process (any <=0 are ignored) + * @param count number of nodes to process + * @param is_dvc 1 if these are DVC ports, 0 if standard I2C + * @return 0 if ok, -1 on error + */ +static int process_nodes(const void *blob, int node_list[], int count) +{ + int i; + + /* build the i2c_controllers[] for each controller */ + for (i = 0; i < count; i++) { + int node = node_list[i]; + struct spi_bus *bus; + + if (node <= 0) + continue; + + bus = &spi_bus[i]; + if (spi_get_config(blob, node, bus)) { + printf("exynos spi_init: failed to decode bus %d\n", + i); + return -1; + } + + debug("spi: controller bus %d at %p, periph_id %d\n", + i, bus->regs, bus->periph_id); + bus->inited = 1; + bus_count++; + } + + return 0; +} + /* Sadly there is no error return from this function */ void spi_init(void) { - int i; + int count; + +#ifdef CONFIG_OF_CONTROL + int node_list[EXYNOS5_SPI_NUM_CONTROLLERS]; + const void *blob = gd->fdt_blob; + + count = fdtdec_find_aliases_for_id(blob, "spi", + COMPAT_SAMSUNG_EXYNOS_SPI, node_list, + EXYNOS5_SPI_NUM_CONTROLLERS); + if (process_nodes(blob, node_list, count)) + return; + +#else struct spi_bus *bus; - for (i = 0; i < EXYNOS5_SPI_NUM_CONTROLLERS; i++) { - bus = &spi_bus[i]; - bus->regs = get_spi_base(i); - bus->periph_id = PERIPH_ID_SPI0 + i; + for (count = 0; count < EXYNOS5_SPI_NUM_CONTROLLERS; count++) { + bus = &spi_bus[count]; + bus->regs = get_spi_base(count); + bus->periph_id = PERIPH_ID_SPI0 + count; /* Although Exynos5 supports upto 50Mhz speed, * we are setting it to 10Mhz for safe side */ bus->frequency = 10000000; bus->inited = 1; + bus->node = 0; + bus_count = EXYNOS5_SPI_NUM_CONTROLLERS; } +#endif } diff --git a/drivers/spi/kirkwood_spi.c b/drivers/spi/kirkwood_spi.c index a7cda75..de81064 100644 --- a/drivers/spi/kirkwood_spi.c +++ b/drivers/spi/kirkwood_spi.c @@ -41,7 +41,10 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, { struct spi_slave *slave; u32 data; - u32 kwspi_mpp_config[] = { 0, 0 }; + static const u32 kwspi_mpp_config[2][2] = { + { MPP0_SPI_SCn, 0 }, /* if cs == 0 */ + { MPP7_SPI_SCn, 0 } /* if cs != 0 */ + }; if (!spi_cs_is_valid(bus, cs)) return NULL; @@ -68,12 +71,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, writel(KWSPI_IRQMASK, &spireg->irq_mask); /* program mpp registers to select SPI_CSn */ - if (cs) { - kwspi_mpp_config[0] = MPP7_SPI_SCn; - } else { - kwspi_mpp_config[0] = MPP0_SPI_SCn; - } - kirkwood_mpp_conf(kwspi_mpp_config, cs_spi_mpp_back); + kirkwood_mpp_conf(kwspi_mpp_config[cs ? 1 : 0], cs_spi_mpp_back); return slave; } diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c index 7d87050..a5a4c1f 100644 --- a/drivers/usb/gadget/g_dnl.c +++ b/drivers/usb/gadget/g_dnl.c @@ -69,6 +69,7 @@ static struct usb_device_descriptor device_desc = { static struct usb_string g_dnl_string_defs[] = { { 0, manufacturer, }, { 1, product, }, + { } /* end of list */ }; static struct usb_gadget_strings g_dnl_string_tab = { @@ -83,7 +84,12 @@ static struct usb_gadget_strings *g_dnl_composite_strings[] = { static int g_dnl_unbind(struct usb_composite_dev *cdev) { - debug("%s\n", __func__); + struct usb_gadget *gadget = cdev->gadget; + + debug("%s: calling usb_gadget_disconnect for " + "controller '%s'\n", shortname, gadget->name); + usb_gadget_disconnect(gadget); + return 0; } @@ -153,6 +159,10 @@ static int g_dnl_bind(struct usb_composite_dev *cdev) device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); } + debug("%s: calling usb_gadget_connect for " + "controller '%s'\n", shortname, gadget->name); + usb_gadget_connect(gadget); + return 0; error: diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index dd74143..9ce98f0 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -40,7 +40,6 @@ #include <asm/io.h> #include <asm/arch/pxa.h> -#include <usbdescriptors.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <usb/lin_gadget_compat.h> diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 9f0ed06..3ca4c5c 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -21,13 +21,71 @@ */ #include <common.h> +#include <fdtdec.h> +#include <libfdt.h> +#include <malloc.h> #include <usb.h> #include <asm/arch/cpu.h> #include <asm/arch/ehci.h> #include <asm/arch/system.h> #include <asm/arch/power.h> +#include <asm-generic/errno.h> +#include <linux/compat.h> #include "ehci.h" +/* Declare global data pointer */ +DECLARE_GLOBAL_DATA_PTR; + +/** + * Contains pointers to register base addresses + * for the usb controller. + */ +struct exynos_ehci { + struct exynos_usb_phy *usb; + unsigned int *hcd; +}; + +static int exynos_usb_parse_dt(const void *blob, struct exynos_ehci *exynos) +{ + unsigned int node; + int depth; + + node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_EHCI); + if (node <= 0) { + debug("EHCI: Can't get device node for ehci\n"); + return -ENODEV; + } + + /* + * Get the base address for EHCI controller from the device node + */ + exynos->hcd = (unsigned int *)fdtdec_get_addr(blob, node, "reg"); + if (exynos->hcd == NULL) { + debug("Can't get the EHCI register address\n"); + return -ENXIO; + } + + depth = 0; + node = fdtdec_next_compatible_subnode(blob, node, + COMPAT_SAMSUNG_EXYNOS_USB_PHY, &depth); + if (node <= 0) { + debug("EHCI: Can't get device node for usb-phy controller\n"); + return -ENODEV; + } + + /* + * Get the base address for usbphy from the device node + */ + exynos->usb = (struct exynos_usb_phy *)fdtdec_get_addr(blob, node, + "reg"); + if (exynos->usb == NULL) { + debug("Can't get the usbphy register address\n"); + return -ENXIO; + } + + return 0; +} + /* Setup the EHCI host controller. */ static void setup_usb_phy(struct exynos_usb_phy *usb) { @@ -86,12 +144,20 @@ static void reset_usb_phy(struct exynos_usb_phy *usb) */ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) { - struct exynos_usb_phy *usb; + struct exynos_ehci *exynos = NULL; + + exynos = (struct exynos_ehci *) + kzalloc(sizeof(struct exynos_ehci), GFP_KERNEL); + if (!exynos) { + debug("failed to allocate exynos ehci context\n"); + return -ENOMEM; + } - usb = (struct exynos_usb_phy *)samsung_get_base_usb_phy(); - setup_usb_phy(usb); + exynos_usb_parse_dt(gd->fdt_blob, exynos); - *hccr = (struct ehci_hccr *)samsung_get_base_usb_ehci(); + setup_usb_phy(exynos->usb); + + *hccr = (struct ehci_hccr *)(exynos->hcd); *hcor = (struct ehci_hcor *)((uint32_t) *hccr + HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); @@ -99,6 +165,8 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) (uint32_t)*hccr, (uint32_t)*hcor, (uint32_t)HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); + kfree(exynos); + return 0; } @@ -108,10 +176,20 @@ int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor) */ int ehci_hcd_stop(int index) { - struct exynos_usb_phy *usb; + struct exynos_ehci *exynos = NULL; + + exynos = (struct exynos_ehci *) + kzalloc(sizeof(struct exynos_ehci), GFP_KERNEL); + if (!exynos) { + debug("failed to allocate exynos ehci context\n"); + return -ENOMEM; + } + + exynos_usb_parse_dt(gd->fdt_blob, exynos); + + reset_usb_phy(exynos->usb); - usb = (struct exynos_usb_phy *)samsung_get_base_usb_phy(); - reset_usb_phy(usb); + kfree(exynos); return 0; } diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 9532dd9..efd711d 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -41,7 +41,8 @@ int usb_cpu_init(void) writel(get_pllb_init(), &pmc->pllbr); while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != AT91_PMC_LOCKB) ; -#elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) +#elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \ + defined(CONFIG_AT91SAM9X5) /* Enable UPLL */ writel(readl(&pmc->uckr) | AT91_PMC_UPLLEN | AT91_PMC_BIASEN, &pmc->uckr); @@ -81,7 +82,8 @@ int usb_cpu_stop(void) writel(0, &pmc->pllbr); while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != 0) ; -#elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) +#elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \ + defined(CONFIG_AT91SAM9X5) /* Disable UPLL */ writel(readl(&pmc->uckr) & (~AT91_PMC_UPLLEN), &pmc->uckr); while ((readl(&pmc->sr) & AT91_PMC_LOCKU) == AT91_PMC_LOCKU) diff --git a/drivers/video/exynos_dp.c b/drivers/video/exynos_dp.c index 53e4101..d72fa56 100644 --- a/drivers/video/exynos_dp.c +++ b/drivers/video/exynos_dp.c @@ -857,7 +857,6 @@ unsigned int exynos_init_dp(void) { unsigned int ret; struct edp_device_info *edp_info; - struct edp_disp_info disp_info; edp_info = kzalloc(sizeof(struct edp_device_info), GFP_KERNEL); if (!edp_info) { @@ -870,7 +869,6 @@ unsigned int exynos_init_dp(void) debug("failed to get edp_info data.\n"); return -EFAULT; } - disp_info = edp_info->disp_info; exynos_dp_disp_info(&edp_info->disp_info); diff --git a/drivers/video/exynos_fb.c b/drivers/video/exynos_fb.c index d9a3f9a..ee0ed06 100644 --- a/drivers/video/exynos_fb.c +++ b/drivers/video/exynos_fb.c @@ -63,8 +63,12 @@ static void exynos_lcd_init_mem(void *lcdbase, vidinfo_t *vid) static void exynos_lcd_init(vidinfo_t *vid) { exynos_fimd_lcd_init(vid); + + /* Enable flushing after LCD writes if requested */ + lcd_set_flush_dcache(1); } +#ifdef CONFIG_CMD_BMP static void draw_logo(void) { int x, y; @@ -87,6 +91,7 @@ static void draw_logo(void) addr = panel_info.logo_addr; bmp_display(addr, x, y); } +#endif static void lcd_panel_on(vidinfo_t *vid) { @@ -145,7 +150,9 @@ void lcd_enable(void) if (panel_info.logo_on) { memset(lcd_base, 0, panel_width * panel_height * (NBITS(panel_info.vl_bpix) >> 3)); +#ifdef CONFIG_CMD_BMP draw_logo(); +#endif } lcd_panel_on(&panel_info); diff --git a/drivers/video/exynos_fimd.c b/drivers/video/exynos_fimd.c index 06eae2e..2efe6a6 100644 --- a/drivers/video/exynos_fimd.c +++ b/drivers/video/exynos_fimd.c @@ -88,14 +88,18 @@ static void exynos_fimd_set_par(unsigned int win_id) /* DATAPATH is DMA */ cfg |= EXYNOS_WINCON_DATAPATH_DMA; - /* bpp is 32 */ - cfg |= EXYNOS_WINCON_WSWP_ENABLE; + if (pvid->logo_on) /* To get proprietary LOGO */ + cfg |= EXYNOS_WINCON_WSWP_ENABLE; + else /* To get output console on LCD */ + cfg |= EXYNOS_WINCON_HAWSWP_ENABLE; /* dma burst is 16 */ cfg |= EXYNOS_WINCON_BURSTLEN_16WORD; - /* pixel format is unpacked RGB888 */ - cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888; + if (pvid->logo_on) /* To get proprietary LOGO */ + cfg |= EXYNOS_WINCON_BPPMODE_24BPP_888; + else /* To get output console on LCD */ + cfg |= EXYNOS_WINCON_BPPMODE_16BPP_565; writel(cfg, (unsigned int)&fimd_ctrl->wincon0 + EXYNOS_WINCON(win_id)); |