From 9169543d1e3361313041184d2a66fe08ce0fcb93 Mon Sep 17 00:00:00 2001 From: Ajay Kumar Date: Thu, 4 Apr 2013 10:25:19 -0400 Subject: video: exynos_fb: Add the missing #else clause This patch fixes a bug introduced while adding DT support to Exynos FIMD driver: commit c23f3157d69bbb6c044256870f745f195b12431e Author: Ajay Kumar Date: Thu Feb 21 23:53:01 2013 +0000 video: exynos_fb: add DT support for FIMD driver Even though this part of code was missing, things were working fine on Exynos5250 because, samsung_get_base_fimd() used to give the correct base address for Exynos5250 FIMD. Signed-off-by: Ajay Kumar Acked-by: Donghwa Lee Signed-off-by: Minkyu Kang --- drivers/video/exynos_fimd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/exynos_fimd.c b/drivers/video/exynos_fimd.c index 33599499ee..7243ea335e 100644 --- a/drivers/video/exynos_fimd.c +++ b/drivers/video/exynos_fimd.c @@ -280,8 +280,9 @@ void exynos_fimd_lcd_init(vidinfo_t *vid) node, "reg"); if (fimd_ctrl == NULL) debug("Can't get the FIMD base address\n"); -#endif +#else fimd_ctrl = (struct exynos_fb *)samsung_get_base_fimd(); +#endif offset = exynos_fimd_get_base_offset(); -- cgit From 2c07bb9b53dded1d49731bb9cab589002b89286f Mon Sep 17 00:00:00 2001 From: Amar Date: Thu, 4 Apr 2013 02:27:06 -0400 Subject: EXYNOS5: I2C: Add FDT and non-FDT support for I2C This patch updates the function board_i2c_init() to add support for both FDT and non-FDT for I2C, and initialise the I2C channels. Signed-off-by: Amar Acked-by: Simon Glass Signed-off-by: Minkyu Kang --- drivers/i2c/s3c24x0_i2c.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 46d25061ee..3fc1c5b03b 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -515,11 +515,12 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) len) != 0); } -#ifdef CONFIG_OF_CONTROL void board_i2c_init(const void *blob) { + int i; +#ifdef CONFIG_OF_CONTROL int node_list[CONFIG_MAX_I2C_NUM]; - int count, i; + int count; count = fdtdec_find_aliases_for_id(blob, "i2c", COMPAT_SAMSUNG_S3C2440_I2C, node_list, @@ -539,8 +540,15 @@ void board_i2c_init(const void *blob) bus->bus_num = i2c_busses++; exynos_pinmux_config(bus->id, 0); } +#else + for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) { + exynos_pinmux_config((PERIPH_ID_I2C0 + i), + PINMUX_FLAG_NONE); + } +#endif } +#ifdef CONFIG_OF_CONTROL static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx) { if (bus_idx < i2c_busses) -- cgit From d4ec8f08856bea73a0def00a7f09dff6a3541604 Mon Sep 17 00:00:00 2001 From: Rajeshwari Shinde Date: Mon, 24 Jun 2013 16:47:22 +0530 Subject: S5P: Serial: Add fdt support to driver This patch adds FDT support to the serial s5p driver. At present disabling the serial console (from the device tree) crashes U-Boot. Add checks for this case, so that execution can continue without a serial console. It also enables the serial_s5p driver recognize the silent_console option. Signed-off-by: Abhilash Kesavan Signed-off-by: Gabe Black Signed-off-by: Simon Glass Signed-off-by: Rajeshwari Shinde Signed-off-by: Minkyu Kang --- drivers/serial/serial_s5p.c | 78 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index e65125ccd7..6836c7a225 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include @@ -34,10 +35,21 @@ DECLARE_GLOBAL_DATA_PTR; #define RX_FIFO_FULL_MASK (1 << 8) #define TX_FIFO_FULL_MASK (1 << 24) +/* Information about a serial port */ +struct fdt_serial { + u32 base_addr; /* address of registers in physical memory */ + u8 port_id; /* uart port number */ + u8 enabled; /* 1 if enabled, 0 if disabled */ +} config __attribute__ ((section(".data"))); + static inline struct s5p_uart *s5p_get_base_uart(int dev_index) { +#ifdef CONFIG_OF_CONTROL + return (struct s5p_uart *)(config.base_addr); +#else u32 offset = dev_index * sizeof(struct s5p_uart); return (struct s5p_uart *)(samsung_get_base_uart() + offset); +#endif } /* @@ -73,6 +85,16 @@ void serial_setbrg_dev(const int dev_index) u32 baudrate = gd->baudrate; u32 val; +#if defined(CONFIG_SILENT_CONSOLE) && \ + defined(CONFIG_OF_CONTROL) && \ + !defined(CONFIG_SPL_BUILD) + if (fdtdec_get_config_int(gd->fdt_blob, "silent_console", 0)) + gd->flags |= GD_FLG_SILENT; +#endif + + if (!config.enabled) + return; + val = uclk / baudrate; writel(val / 16 - 1, &uart->ubrdiv); @@ -133,6 +155,9 @@ int serial_getc_dev(const int dev_index) { struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + if (!config.enabled) + return 0; + /* wait for character to arrive */ while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK | RX_FIFO_FULL_MASK))) { @@ -150,6 +175,9 @@ void serial_putc_dev(const char c, const int dev_index) { struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + if (!config.enabled) + return; + /* wait for room in the tx FIFO */ while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) { if (serial_err_check(dev_index, 1)) @@ -170,6 +198,9 @@ int serial_tstc_dev(const int dev_index) { struct s5p_uart *const uart = s5p_get_base_uart(dev_index); + if (!config.enabled) + return 0; + return (int)(readl(&uart->utrstat) & 0x1); } @@ -212,8 +243,54 @@ DECLARE_S5P_SERIAL_FUNCTIONS(3); struct serial_device s5p_serial3_device = INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3"); +#ifdef CONFIG_OF_CONTROL +int fdtdec_decode_console(int *index, struct fdt_serial *uart) +{ + const void *blob = gd->fdt_blob; + int node; + + node = fdt_path_offset(blob, "console"); + if (node < 0) + return node; + + uart->base_addr = fdtdec_get_addr(blob, node, "reg"); + if (uart->base_addr == FDT_ADDR_T_NONE) + return -FDT_ERR_NOTFOUND; + + uart->port_id = fdtdec_get_int(blob, node, "id", -1); + uart->enabled = fdtdec_get_is_enabled(blob, node); + + return 0; +} +#endif + __weak struct serial_device *default_serial_console(void) { +#ifdef CONFIG_OF_CONTROL + int index = 0; + + if ((!config.base_addr) && (fdtdec_decode_console(&index, &config))) { + debug("Cannot decode default console node\n"); + return NULL; + } + + switch (config.port_id) { + case 0: + return &s5p_serial0_device; + case 1: + return &s5p_serial1_device; + case 2: + return &s5p_serial2_device; + case 3: + return &s5p_serial3_device; + default: + debug("Unknown config.port_id: %d", config.port_id); + break; + } + + return NULL; +#else + config.enabled = 1; #if defined(CONFIG_SERIAL0) return &s5p_serial0_device; #elif defined(CONFIG_SERIAL1) @@ -225,6 +302,7 @@ __weak struct serial_device *default_serial_console(void) #else #error "CONFIG_SERIAL? missing." #endif +#endif } void s5p_serial_initialize(void) -- cgit From 79a6fcf2573e1a2ccdc8703f8e62d6efe890fdf4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 15 Jun 2013 17:56:59 +0800 Subject: gpio: s3c2440_gpio: Fix wrong writel arguments Current code had writel arguments the wrong way around, fix it. Signed-off-by: Axel Lin Reviewed-by: Marek Vasut Signed-off-by: Minkyu Kang --- drivers/gpio/s3c2440_gpio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/s3c2440_gpio.c b/drivers/gpio/s3c2440_gpio.c index 43bbf1160c..09b04eb94a 100644 --- a/drivers/gpio/s3c2440_gpio.c +++ b/drivers/gpio/s3c2440_gpio.c @@ -61,7 +61,7 @@ int gpio_set_value(unsigned gpio, int value) else l &= ~bit; - return writel(port, l); + return writel(l, port); } int gpio_get_value(unsigned gpio) @@ -85,11 +85,11 @@ int gpio_free(unsigned gpio) int gpio_direction_input(unsigned gpio) { - return writel(GPIO_FULLPORT(gpio), GPIO_INPUT << GPIO_BIT(gpio)); + return writel(GPIO_INPUT << GPIO_BIT(gpio), GPIO_FULLPORT(gpio)); } int gpio_direction_output(unsigned gpio, int value) { - writel(GPIO_FULLPORT(gpio), GPIO_OUTPUT << GPIO_BIT(gpio)); + writel(GPIO_OUTPUT << GPIO_BIT(gpio), GPIO_FULLPORT(gpio)); return gpio_set_value(gpio, value); } -- cgit From 70125f341152c3f29d5552c5490cc5eb15a0215d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 15 Jun 2013 22:19:45 +0800 Subject: gpio: s5p_gpio: Call s5p_gpio_set_value() instead of open-code Call s5p_gpio_set_value() to avoid code duplication. Signed-off-by: Axel Lin Signed-off-by: Minkyu Kang --- drivers/gpio/s5p_gpio.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c index 656bf4a06c..4efb768551 100644 --- a/drivers/gpio/s5p_gpio.c +++ b/drivers/gpio/s5p_gpio.c @@ -48,15 +48,8 @@ void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg) void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, int gpio, int en) { - unsigned int value; - s5p_gpio_cfg_pin(bank, gpio, GPIO_OUTPUT); - - value = readl(&bank->dat); - value &= ~DAT_MASK(gpio); - if (en) - value |= DAT_SET(gpio); - writel(value, &bank->dat); + s5p_gpio_set_value(bank, gpio, en); } void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio) -- cgit From 8d4c4ffb95d528f6a709bf68da5e0beb0f4ee72f Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Thu, 9 May 2013 07:19:52 +0200 Subject: spi: mxc_spi: Fix pre and post divider calculation Fix two issues with the calculation of pre_div and post_div: 1. pre_div: While the calculation of pre_div looks correct, to set the CONREG[15-12] bits pre_div needs to be decremented by 1: The i.MX 6Dual/6Quad Applications Processor Reference Manual (IMX6DQRM Rev. 0, 11/2012) states: CONREG[15-12]: PRE_DIVIDER 0000 Divide by 1 0001 Divide by 2 0010 Divide by 3 ... 1101 Divide by 14 1110 Divide by 15 1111 Divide by 16 I.e. if we want to divide by 2, we have to write 1 to CONREG[15-12]. 2. In case the post divider becomes necessary, pre_div will be divided by 16. So set pre_div to 16, too. And not 15. Both issues above are tested using the following examples: clk_src = 60000000 (60MHz, default i.MX6 ECSPI clock) a) max_hz == 23000000 (23MHz, max i.MX6 ECSPI read clock) -> pre_div = 3 (divide by 3 => CONREG[15-12] == 2) -> post_div = 0 (divide by 1 => CONREG[11- 8] == 0) => 60MHz / 3 = 20MHz SPI clock b) max_hz == 2000000 (2MHz) -> pre_div = 16 (divide by 16 => CONREG[15-12] == 15) -> post_div = 1 (divide by 2 => CONREG[11- 8] == 1) => 60MHz / 32 = 1.875MHz SPI clock c) max_hz == 1000000 (1MHz) -> pre_div = 16 (divide by 16 => CONREG[15-12] == 15) -> post_div = 2 (divide by 4 => CONREG[11- 8] == 2) => 60MHz / 64 = 937.5kHz SPI clock d) max_hz == 500000 (500kHz) -> pre_div = 16 (divide by 16 => CONREG[15-12] == 15) -> post_div = 3 (divide by 8 => CONREG[11- 8] == 3) => 60MHz / 128 = 468.75kHz SPI clock Signed-off-by: Dirk Behme --- drivers/spi/mxc_spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index 5bed858787..b553a9c596 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -128,7 +128,7 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, unsigned int max_hz, unsigned int mode) { u32 clk_src = mxc_get_clock(MXC_CSPI_CLK); - s32 pre_div = 0, post_div = 0, i, reg_ctrl, reg_config; + s32 pre_div = 1, post_div = 0, i, reg_ctrl, reg_config; u32 ss_pol = 0, sclkpol = 0, sclkpha = 0; struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; @@ -154,7 +154,7 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, pre_div = DIV_ROUND_UP(clk_src, max_hz); if (pre_div > 16) { post_div = pre_div / 16; - pre_div = 15; + pre_div = 16; } if (post_div != 0) { for (i = 0; i < 16; i++) { @@ -174,7 +174,7 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_SELCHAN(3)) | MXC_CSPICTRL_SELCHAN(cs); reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_PREDIV(0x0F)) | - MXC_CSPICTRL_PREDIV(pre_div); + MXC_CSPICTRL_PREDIV(pre_div - 1); reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_POSTDIV(0x0F)) | MXC_CSPICTRL_POSTDIV(post_div); -- cgit From 9a30903b44a63861de93d5beaaf4c91173bbac0c Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Sat, 11 May 2013 07:25:54 +0200 Subject: spi: mxc_spi: Update pre and post divider algorithm The spi clock divisor is of the form x * (2**y), or x << y, where x is 1 to 16, and y is 0 to 15. Note the similarity with floating point numbers. Convert the desired divisor to the smallest number which is >= desired divisor, and can be represented in this form. The previous algorithm chose a divisor which could be almost twice as large as needed. Signed-off-by: Troy Kisky Signed-off-by: Dirk Behme --- drivers/spi/mxc_spi.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index b553a9c596..0eca7767e0 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -128,8 +128,8 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, unsigned int max_hz, unsigned int mode) { u32 clk_src = mxc_get_clock(MXC_CSPI_CLK); - s32 pre_div = 1, post_div = 0, i, reg_ctrl, reg_config; - u32 ss_pol = 0, sclkpol = 0, sclkpha = 0; + s32 reg_ctrl, reg_config; + u32 ss_pol = 0, sclkpol = 0, sclkpha = 0, pre_div = 0, post_div = 0; struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; if (max_hz == 0) { @@ -147,26 +147,20 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, reg_ctrl |= MXC_CSPICTRL_EN; reg_write(®s->ctrl, reg_ctrl); - /* - * The following computation is taken directly from Freescale's code. - */ if (clk_src > max_hz) { - pre_div = DIV_ROUND_UP(clk_src, max_hz); - if (pre_div > 16) { - post_div = pre_div / 16; - pre_div = 16; - } - if (post_div != 0) { - for (i = 0; i < 16; i++) { - if ((1 << i) >= post_div) - break; - } - if (i == 16) { + pre_div = (clk_src - 1) / max_hz; + /* fls(1) = 1, fls(0x80000000) = 32, fls(16) = 5 */ + post_div = fls(pre_div); + if (post_div > 4) { + post_div -= 4; + if (post_div >= 16) { printf("Error: no divider for the freq: %d\n", max_hz); return -1; } - post_div = i; + pre_div >>= post_div; + } else { + post_div = 0; } } @@ -174,7 +168,7 @@ static s32 spi_cfg_mxc(struct mxc_spi_slave *mxcs, unsigned int cs, reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_SELCHAN(3)) | MXC_CSPICTRL_SELCHAN(cs); reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_PREDIV(0x0F)) | - MXC_CSPICTRL_PREDIV(pre_div - 1); + MXC_CSPICTRL_PREDIV(pre_div); reg_ctrl = (reg_ctrl & ~MXC_CSPICTRL_POSTDIV(0x0F)) | MXC_CSPICTRL_POSTDIV(post_div); -- cgit From 2dbe64ca249fabab2195a30056a0bd645a4a9152 Mon Sep 17 00:00:00 2001 From: Eric Nelson Date: Sat, 15 Jun 2013 16:09:55 -0700 Subject: dwc_ahsata: Allow use with dcache enabled Signed-off-by: Eric Nelson --- drivers/block/dwc_ahsata.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/block/dwc_ahsata.c b/drivers/block/dwc_ahsata.c index c9b71f7e1f..98f2c52ee3 100644 --- a/drivers/block/dwc_ahsata.c +++ b/drivers/block/dwc_ahsata.c @@ -447,10 +447,13 @@ static int ahci_exec_ata_cmd(struct ahci_probe_ent *probe_ent, if (buf && buf_len) sg_count = ahci_fill_sg(probe_ent, port, buf, buf_len); opts = (sizeof(struct sata_fis_h2d) >> 2) | (sg_count << 16); - if (is_write) + if (is_write) { opts |= 0x40; + flush_cache((ulong)buf, buf_len); + } ahci_fill_cmd_slot(pp, cmd_slot, opts); + flush_cache((int)(pp->cmd_slot), AHCI_PORT_PRIV_DMA_SZ); writel_with_flush(1 << cmd_slot, &(port_mmio->ci)); if (waiting_for_cmd_completed((u8 *)&(port_mmio->ci), @@ -458,8 +461,12 @@ static int ahci_exec_ata_cmd(struct ahci_probe_ent *probe_ent, printf("timeout exit!\n"); return -1; } + invalidate_dcache_range((int)(pp->cmd_slot), + (int)(pp->cmd_slot)+AHCI_PORT_PRIV_DMA_SZ); debug("ahci_exec_ata_cmd: %d byte transferred.\n", pp->cmd_slot->status); + if (!is_write) + invalidate_dcache_range((ulong)buf, (ulong)buf+buf_len); return buf_len; } @@ -468,7 +475,8 @@ static void ahci_set_feature(u8 dev, u8 port) { struct ahci_probe_ent *probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; memset(cfis, 0, sizeof(struct sata_fis_h2d)); cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; @@ -615,7 +623,8 @@ static void dwc_ahsata_identify(int dev, u16 *id) { struct ahci_probe_ent *probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; memset(cfis, 0, sizeof(struct sata_fis_h2d)); @@ -645,7 +654,8 @@ static u32 dwc_ahsata_rw_cmd(int dev, u32 start, u32 blkcnt, { struct ahci_probe_ent *probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; u32 block; @@ -675,7 +685,8 @@ void dwc_ahsata_flush_cache(int dev) { struct ahci_probe_ent *probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; memset(cfis, 0, sizeof(struct sata_fis_h2d)); @@ -692,7 +703,8 @@ static u32 dwc_ahsata_rw_cmd_ext(int dev, u32 start, lbaint_t blkcnt, { struct ahci_probe_ent *probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; u64 block; @@ -728,7 +740,8 @@ u32 dwc_ahsata_rw_ncq_cmd(int dev, u32 start, lbaint_t blkcnt, { struct ahci_probe_ent *probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; u64 block; @@ -769,7 +782,8 @@ void dwc_ahsata_flush_cache_ext(int dev) { struct ahci_probe_ent *probe_ent = (struct ahci_probe_ent *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; + struct sata_fis_h2d h2d __aligned(ARCH_DMA_MINALIGN); + struct sata_fis_h2d *cfis = &h2d; u8 port = probe_ent->hard_port_no; memset(cfis, 0, sizeof(struct sata_fis_h2d)); @@ -912,7 +926,9 @@ int scan_sata(int dev) u8 port = probe_ent->hard_port_no; block_dev_desc_t *pdev = &(sata_dev_desc[dev]); - id = (u16 *)malloc(ATA_ID_WORDS * 2); + id = (u16 *)memalign(ARCH_DMA_MINALIGN, + roundup(ARCH_DMA_MINALIGN, + (ATA_ID_WORDS * 2))); if (!id) { printf("id malloc failed\n\r"); return -1; -- cgit From 620ca1c1740e655d6ae682399fc2f035b98f399e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 26 Jun 2013 16:08:13 -0300 Subject: video: mxsfb: Break the line in videomode message Currently we have the following on boot: CPU: Freescale i.MX28 rev1.2 at 454 MHz BOOT: SSP SD/MMC #0, 3V3 DRAM: 128 MiB MMC: MXS MMC: 0 Video: MXSFB: 'videomode' variable not set!In: serial Break the line of the warning message in order to have a better reading format. Signed-off-by: Fabio Estevam --- drivers/video/mxsfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/video/mxsfb.c b/drivers/video/mxsfb.c index b189419358..b0f7ef8d47 100644 --- a/drivers/video/mxsfb.c +++ b/drivers/video/mxsfb.c @@ -137,7 +137,7 @@ void *video_hw_init(void) /* Suck display configuration from "videomode" variable */ penv = getenv("videomode"); if (!penv) { - printf("MXSFB: 'videomode' variable not set!"); + puts("MXSFB: 'videomode' variable not set!\n"); return NULL; } -- cgit From b0857c45c1f535069acf90e671b5e4b6cf662caf Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Mon, 10 Jun 2013 18:18:04 +0200 Subject: usb: omap: ulpi: fix ulpi transceiver access This patch fix the omap access to the transceiver configuration registers using the ulpi bus. As reported by the documentation the bit31 is used only to check if the transaction is done or still running and the reading and writing operation have different offset and have different values. What we need to do at the end of a transaction is leave the bus in done state. Anyway an error using the ulpi omap register is not recoverable so any error give out the usage of this interface. Tested on a custom OMAP5430 board with a TUSB1210 ULPI PHY on USBB1. Signed-off-by: Michael Trimarchi Acked-by: Igor Grinberg Tested-by: Lubomir Popov Cc: Stefano Babic Cc: Marek Vasut Cc: Tom Rini --- drivers/usb/ulpi/omap-ulpi-viewport.c | 42 ++++++++--------------------------- 1 file changed, 9 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/ulpi/omap-ulpi-viewport.c b/drivers/usb/ulpi/omap-ulpi-viewport.c index 3c1ea1a524..4db7fa43ce 100644 --- a/drivers/usb/ulpi/omap-ulpi-viewport.c +++ b/drivers/usb/ulpi/omap-ulpi-viewport.c @@ -22,18 +22,19 @@ #include #include -#define OMAP_ULPI_WR_OPSEL (3 << 21) -#define OMAP_ULPI_ACCESS (1 << 31) +#define OMAP_ULPI_WR_OPSEL (2 << 22) +#define OMAP_ULPI_RD_OPSEL (3 << 22) +#define OMAP_ULPI_START (1 << 31) /* - * Wait for the ULPI Access to complete + * Wait for having ulpi in done state */ static int ulpi_wait(struct ulpi_viewport *ulpi_vp, u32 mask) { int timeout = CONFIG_USB_ULPI_TIMEOUT; while (--timeout) { - if ((readl(ulpi_vp->viewport_addr) & mask)) + if (!(readl(ulpi_vp->viewport_addr) & mask)) return 0; udelay(1); @@ -42,27 +43,6 @@ static int ulpi_wait(struct ulpi_viewport *ulpi_vp, u32 mask) return ULPI_ERROR; } -/* - * Wake the ULPI PHY up for communication - * - * returns 0 on success. - */ -static int ulpi_wakeup(struct ulpi_viewport *ulpi_vp) -{ - int err; - - if (readl(ulpi_vp->viewport_addr) & OMAP_ULPI_ACCESS) - return 0; /* already awake */ - - writel(OMAP_ULPI_ACCESS, ulpi_vp->viewport_addr); - - err = ulpi_wait(ulpi_vp, OMAP_ULPI_ACCESS); - if (err) - debug("ULPI wakeup timed out\n"); - - return err; -} - /* * Issue a ULPI read/write request */ @@ -70,13 +50,9 @@ static int ulpi_request(struct ulpi_viewport *ulpi_vp, u32 value) { int err; - err = ulpi_wakeup(ulpi_vp); - if (err) - return err; - writel(value, ulpi_vp->viewport_addr); - err = ulpi_wait(ulpi_vp, OMAP_ULPI_ACCESS); + err = ulpi_wait(ulpi_vp, OMAP_ULPI_START); if (err) debug("ULPI request timed out\n"); @@ -85,7 +61,7 @@ static int ulpi_request(struct ulpi_viewport *ulpi_vp, u32 value) int ulpi_write(struct ulpi_viewport *ulpi_vp, u8 *reg, u32 value) { - u32 val = ((ulpi_vp->port_num & 0xf) << 24) | + u32 val = OMAP_ULPI_START | (((ulpi_vp->port_num + 1) & 0xf) << 24) | OMAP_ULPI_WR_OPSEL | ((u32)reg << 16) | (value & 0xff); return ulpi_request(ulpi_vp, val); @@ -94,8 +70,8 @@ int ulpi_write(struct ulpi_viewport *ulpi_vp, u8 *reg, u32 value) u32 ulpi_read(struct ulpi_viewport *ulpi_vp, u8 *reg) { int err; - u32 val = ((ulpi_vp->port_num & 0xf) << 24) | - OMAP_ULPI_WR_OPSEL | ((u32)reg << 16); + u32 val = OMAP_ULPI_START | (((ulpi_vp->port_num + 1) & 0xf) << 24) | + OMAP_ULPI_RD_OPSEL | ((u32)reg << 16); err = ulpi_request(ulpi_vp, val); if (err) -- cgit From 87bd05d78f0f5765f3d3e1517c76794c82dab7cc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 21 Jun 2013 18:54:25 +0800 Subject: ARM: OMAP: GPIO: Fix valid range and enable usage of all GPIOs on OMAP5 The omap_gpio driver is used by AM33XX, OMAP3/4, OMAP54XX and DRA7XX SoCs. These SoCs have different gpio count but currently omap_gpio driver uses hard coded 192 which is wrong. This patch fixes this issue by: 1. Move define of OMAP_MAX_GPIO to all arch/arm/include/asm/arch-omap*/gpio.h. 2. Update gpio bank settings and enable GPIO modules 7 & 8 clocks for OMAP5. Thanks for Lubomir Popov to provide valuable comments to fix this issue. Signed-off-by: Axel Lin Tested-by: Lubomir Popov Acked-by: Heiko Schocher --- drivers/gpio/omap_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c index a30d7f0603..f16e9ae4d2 100644 --- a/drivers/gpio/omap_gpio.c +++ b/drivers/gpio/omap_gpio.c @@ -55,7 +55,7 @@ static inline int get_gpio_index(int gpio) int gpio_is_valid(int gpio) { - return (gpio >= 0) && (gpio < 192); + return (gpio >= 0) && (gpio < OMAP_MAX_GPIO); } static int check_gpio(int gpio) -- cgit From 9dfa3d0734df4aad107def2c900d1514ac7510ac Mon Sep 17 00:00:00 2001 From: Ɓukasz Majewski Date: Tue, 25 Jun 2013 15:28:15 +0200 Subject: power:bat:trats: Break battery charging with ctrl+C Add support for disabling battery charging with ctrl+C keyboard combination pressed. Moreover the battery update is done more frequently. Signed-off-by: Lukasz Majewski Cc: Tom Rini Signed-off-by: Minkyu Kang --- drivers/power/battery/bat_trats.c | 13 +++++++++---- drivers/power/power_core.c | 3 ++- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/power/battery/bat_trats.c b/drivers/power/battery/bat_trats.c index ca0d214659..97a9661150 100644 --- a/drivers/power/battery/bat_trats.c +++ b/drivers/power/battery/bat_trats.c @@ -41,18 +41,23 @@ static int power_battery_charge(struct pmic *bat) for (k = 0; bat->chrg->chrg_bat_present(p_bat->chrg) && bat->chrg->chrg_type(p_bat->muic) && battery->state_of_chrg < 100; k++) { - udelay(10000000); - puts("."); + udelay(2000000); + if (!(k % 5)) + puts("."); bat->fg->fg_battery_update(p_bat->fg, bat); - if (k == 100) { + if (k == 200) { debug(" %d [V]", battery->voltage_uV); puts("\n"); k = 0; } + if (ctrlc()) { + printf("\nCharging disabled on request.\n"); + goto exit; + } } - + exit: bat->chrg->chrg_state(p_bat->chrg, CHARGER_DISABLE, 0); return 0; diff --git a/drivers/power/power_core.c b/drivers/power/power_core.c index 90df2c58c4..f16b9dc066 100644 --- a/drivers/power/power_core.c +++ b/drivers/power/power_core.c @@ -205,7 +205,8 @@ int do_pmic(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) if (strcmp(argv[3], "charge") == 0) { if (p->pbat) { - printf("PRINT BAT charge %s\n", p->name); + printf("BAT: %s charging (ctrl+c to break)\n", + p->name); if (p->low_power_mode) p->low_power_mode(); if (p->pbat->battery_charge) -- cgit From 1ae76d438b602fe8be1f0ef8b8ce47c89d371047 Mon Sep 17 00:00:00 2001 From: Amar Date: Wed, 10 Jul 2013 10:42:29 +0530 Subject: EXYNOS: Resolve the i2c compilation error This patch resolves the below mentioned compilation error of i2c driver for non-FDT case Compilation error: s3c24x0_i2c.c: In function 'board_i2c_init': s3c24x0_i2c.c:544:18: error: 'CONFIG_MAX_I2C_NUM' undeclared (first use in this function) s3c24x0_i2c.c:544:18: note: each undeclared identifier is reported only once for each function it appears in s3c24x0_i2c.c:545:3: warning: implicit declaration of function Signed-off-by: Rajeshwari Shinde Signed-off-by: Amar Signed-off-by: Minkyu Kang --- drivers/i2c/s3c24x0_i2c.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index 3fc1c5b03b..382e4c2ecf 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -515,10 +515,10 @@ int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) len) != 0); } +#ifdef CONFIG_OF_CONTROL void board_i2c_init(const void *blob) { int i; -#ifdef CONFIG_OF_CONTROL int node_list[CONFIG_MAX_I2C_NUM]; int count; @@ -540,15 +540,8 @@ void board_i2c_init(const void *blob) bus->bus_num = i2c_busses++; exynos_pinmux_config(bus->id, 0); } -#else - for (i = 0; i < CONFIG_MAX_I2C_NUM; i++) { - exynos_pinmux_config((PERIPH_ID_I2C0 + i), - PINMUX_FLAG_NONE); - } -#endif } -#ifdef CONFIG_OF_CONTROL static struct s3c24x0_i2c_bus *get_bus(unsigned int bus_idx) { if (bus_idx < i2c_busses) -- cgit From 7e44d9320ed4a9994b97eb1c9b2efd04491ff431 Mon Sep 17 00:00:00 2001 From: Jim Lin Date: Fri, 21 Jun 2013 19:05:47 +0800 Subject: ARM: Tegra: USB: EHCI: Add support for Tegra30/Tegra114 Tegra30 and Tegra114 are compatible except PLL parameters. Tested on Tegra30 Cardhu, and Tegra114 Dalmore platforms. All works well. Signed-off-by: Jim Lin Signed-off-by: Tom Warren --- drivers/usb/host/ehci-tegra.c | 304 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 268 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 554145a250..a9603bc104 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2011 The Chromium OS Authors. - * Copyright (c) 2009-2012 NVIDIA Corporation + * Copyright (c) 2009-2013 NVIDIA Corporation * Copyright (c) 2013 Lucas Stach * * See file CREDITS for list of people who contributed to this @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -35,6 +37,11 @@ #include "ehci.h" +#define USB1_ADDR_MASK 0xFFFF0000 + +#define HOSTPC1_DEVLC 0x84 +#define HOSTPC1_PSPD(x) (((x) >> 25) & 0x3) + #ifdef CONFIG_USB_ULPI #ifndef CONFIG_USB_ULPI_VIEWPORT #error "To use CONFIG_USB_ULPI on Tegra Boards you have to also \ @@ -87,6 +94,8 @@ struct fdt_usb { static struct fdt_usb port[USB_PORTS_MAX]; /* List of valid USB ports */ static unsigned port_count; /* Number of available ports */ +/* Port that needs to clear CSC after Port Reset */ +static u32 port_addr_clear_csc; /* * This table has USB timing parameters for each Oscillator frequency we @@ -129,7 +138,7 @@ static unsigned port_count; /* Number of available ports */ * * 4. The 20 microsecond delay after bias cell operation. */ -static const unsigned usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = { +static const unsigned T20_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = { /* DivN, DivM, DivP, CPCON, LFCON, Delays Debounce, Bias */ { 0x3C0, 0x0D, 0x00, 0xC, 0, 0x02, 0x33, 0x05, 0x7F, 0x7EF4, 5 }, { 0x0C8, 0x04, 0x00, 0x3, 0, 0x03, 0x4B, 0x06, 0xBB, 0xBB80, 7 }, @@ -137,6 +146,22 @@ static const unsigned usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = { { 0x3C0, 0x1A, 0x00, 0xC, 0, 0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 } }; +static const unsigned T30_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = { + /* DivN, DivM, DivP, CPCON, LFCON, Delays Debounce, Bias */ + { 0x3C0, 0x0D, 0x00, 0xC, 1, 0x02, 0x33, 0x09, 0x7F, 0x7EF4, 5 }, + { 0x0C8, 0x04, 0x00, 0x3, 0, 0x03, 0x4B, 0x0C, 0xBB, 0xBB80, 7 }, + { 0x3C0, 0x0C, 0x00, 0xC, 1, 0x02, 0x2F, 0x08, 0x76, 0x7530, 5 }, + { 0x3C0, 0x1A, 0x00, 0xC, 1, 0x04, 0x66, 0x09, 0xFE, 0xFDE8, 9 } +}; + +static const unsigned T114_usb_pll[CLOCK_OSC_FREQ_COUNT][PARAM_COUNT] = { + /* DivN, DivM, DivP, CPCON, LFCON, Delays Debounce, Bias */ + { 0x3C0, 0x0D, 0x00, 0xC, 2, 0x02, 0x33, 0x09, 0x7F, 0x7EF4, 6 }, + { 0x0C8, 0x04, 0x00, 0x3, 2, 0x03, 0x4B, 0x0C, 0xBB, 0xBB80, 8 }, + { 0x3C0, 0x0C, 0x00, 0xC, 2, 0x02, 0x2F, 0x08, 0x76, 0x7530, 5 }, + { 0x3C0, 0x1A, 0x00, 0xC, 2, 0x04, 0x66, 0x09, 0xFE, 0xFDE8, 0xB } +}; + /* UTMIP Idle Wait Delay */ static const u8 utmip_idle_wait_delay = 17; @@ -146,6 +171,33 @@ static const u8 utmip_elastic_limit = 16; /* UTMIP High Speed Sync Start Delay */ static const u8 utmip_hs_sync_start_delay = 9; +struct fdt_usb_controller { + int compat; + /* flag to determine whether controller supports hostpc register */ + u32 has_hostpc:1; + const unsigned *pll_parameter; +}; + +static struct fdt_usb_controller fdt_usb_controllers[] = { + { + .compat = COMPAT_NVIDIA_TEGRA20_USB, + .has_hostpc = 0, + .pll_parameter = (const unsigned *)T20_usb_pll, + }, + { + .compat = COMPAT_NVIDIA_TEGRA30_USB, + .has_hostpc = 1, + .pll_parameter = (const unsigned *)T30_usb_pll, + }, + { + .compat = COMPAT_NVIDIA_TEGRA114_USB, + .has_hostpc = 1, + .pll_parameter = (const unsigned *)T114_usb_pll, + }, +}; + +static struct fdt_usb_controller *controller; + /* * A known hardware issue where Connect Status Change bit of PORTSC register * of USB1 controller will be set after Port Reset. @@ -156,13 +208,52 @@ static const u8 utmip_hs_sync_start_delay = 9; void ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg) { mdelay(50); - if (((u32) status_reg & TEGRA_USB_ADDR_MASK) != TEGRA_USB1_BASE) + /* This is to avoid PORT_ENABLE bit to be cleared in "ehci-hcd.c". */ + if (controller->has_hostpc) + *reg |= EHCI_PS_PE; + + if (((u32)status_reg & TEGRA_USB_ADDR_MASK) != port_addr_clear_csc) return; /* For EHCI_PS_CSC to be cleared in ehci_hcd.c */ if (ehci_readl(status_reg) & EHCI_PS_CSC) *reg |= EHCI_PS_CSC; } +/* + * This ehci_set_usbmode overrides the weak function ehci_set_usbmode + * in "ehci-hcd.c". + */ +void ehci_set_usbmode(int index) +{ + struct fdt_usb *config; + struct usb_ctlr *usbctlr; + uint32_t tmp; + + config = &port[index]; + usbctlr = config->reg; + + tmp = ehci_readl(&usbctlr->usb_mode); + tmp |= USBMODE_CM_HC; + ehci_writel(&usbctlr->usb_mode, tmp); +} + +/* + * This ehci_get_port_speed overrides the weak function ehci_get_port_speed + * in "ehci-hcd.c". + */ +int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg) +{ + uint32_t tmp; + uint32_t *reg_ptr; + + if (controller->has_hostpc) { + reg_ptr = (uint32_t *)((u8 *)&hcor->or_usbcmd + HOSTPC1_DEVLC); + tmp = ehci_readl(reg_ptr); + return HOSTPC1_PSPD(tmp); + } else + return PORTSC_PSPD(reg); +} + /* Put the port into host mode */ static void set_host_mode(struct fdt_usb *config) { @@ -209,6 +300,16 @@ void usbf_reset_controller(struct fdt_usb *config, struct usb_ctlr *usbctlr) setbits_le32(&usbctlr->susp_ctrl, UTMIP_PHY_ENB); } +static const unsigned *get_pll_timing(void) +{ + const unsigned *timing; + + timing = controller->pll_parameter + + clock_get_osc_freq() * PARAM_COUNT; + + return timing; +} + /* set up the UTMI USB controller with the parameters provided */ static int init_utmi_usb_controller(struct fdt_usb *config) { @@ -216,6 +317,8 @@ static int init_utmi_usb_controller(struct fdt_usb *config) int loop_count; const unsigned *timing; struct usb_ctlr *usbctlr = config->reg; + struct clk_rst_ctlr *clkrst; + struct usb_ctlr *usb1ctlr; clock_enable(config->periph_id); @@ -232,35 +335,97 @@ static int init_utmi_usb_controller(struct fdt_usb *config) * To Use the A Session Valid for cable detection logic, VBUS_WAKEUP * mux must be switched to actually use a_sess_vld threshold. */ - if (fdt_gpio_isvalid(&config->vbus_gpio)) { + if (config->dr_mode == DR_MODE_OTG && + fdt_gpio_isvalid(&config->vbus_gpio)) clrsetbits_le32(&usbctlr->usb1_legacy_ctrl, VBUS_SENSE_CTL_MASK, VBUS_SENSE_CTL_A_SESS_VLD << VBUS_SENSE_CTL_SHIFT); - } /* * PLL Delay CONFIGURATION settings. The following parameters control * the bring up of the plls. */ - timing = usb_pll[clock_get_osc_freq()]; - - val = readl(&usbctlr->utmip_misc_cfg1); - clrsetbits_le32(&val, UTMIP_PLLU_STABLE_COUNT_MASK, - timing[PARAM_STABLE_COUNT] << UTMIP_PLLU_STABLE_COUNT_SHIFT); - clrsetbits_le32(&val, UTMIP_PLL_ACTIVE_DLY_COUNT_MASK, - timing[PARAM_ACTIVE_DELAY_COUNT] << - UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT); - writel(val, &usbctlr->utmip_misc_cfg1); - - /* Set PLL enable delay count and crystal frequency count */ - val = readl(&usbctlr->utmip_pll_cfg1); - clrsetbits_le32(&val, UTMIP_PLLU_ENABLE_DLY_COUNT_MASK, - timing[PARAM_ENABLE_DELAY_COUNT] << - UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT); - clrsetbits_le32(&val, UTMIP_XTAL_FREQ_COUNT_MASK, - timing[PARAM_XTAL_FREQ_COUNT] << - UTMIP_XTAL_FREQ_COUNT_SHIFT); - writel(val, &usbctlr->utmip_pll_cfg1); + timing = get_pll_timing(); + + if (!controller->has_hostpc) { + val = readl(&usbctlr->utmip_misc_cfg1); + clrsetbits_le32(&val, UTMIP_PLLU_STABLE_COUNT_MASK, + timing[PARAM_STABLE_COUNT] << + UTMIP_PLLU_STABLE_COUNT_SHIFT); + clrsetbits_le32(&val, UTMIP_PLL_ACTIVE_DLY_COUNT_MASK, + timing[PARAM_ACTIVE_DELAY_COUNT] << + UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT); + writel(val, &usbctlr->utmip_misc_cfg1); + + /* Set PLL enable delay count and crystal frequency count */ + val = readl(&usbctlr->utmip_pll_cfg1); + clrsetbits_le32(&val, UTMIP_PLLU_ENABLE_DLY_COUNT_MASK, + timing[PARAM_ENABLE_DELAY_COUNT] << + UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT); + clrsetbits_le32(&val, UTMIP_XTAL_FREQ_COUNT_MASK, + timing[PARAM_XTAL_FREQ_COUNT] << + UTMIP_XTAL_FREQ_COUNT_SHIFT); + writel(val, &usbctlr->utmip_pll_cfg1); + } else { + clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + + val = readl(&clkrst->crc_utmip_pll_cfg2); + clrsetbits_le32(&val, UTMIP_PLLU_STABLE_COUNT_MASK, + timing[PARAM_STABLE_COUNT] << + UTMIP_PLLU_STABLE_COUNT_SHIFT); + clrsetbits_le32(&val, UTMIP_PLL_ACTIVE_DLY_COUNT_MASK, + timing[PARAM_ACTIVE_DELAY_COUNT] << + UTMIP_PLL_ACTIVE_DLY_COUNT_SHIFT); + writel(val, &clkrst->crc_utmip_pll_cfg2); + + /* Set PLL enable delay count and crystal frequency count */ + val = readl(&clkrst->crc_utmip_pll_cfg1); + clrsetbits_le32(&val, UTMIP_PLLU_ENABLE_DLY_COUNT_MASK, + timing[PARAM_ENABLE_DELAY_COUNT] << + UTMIP_PLLU_ENABLE_DLY_COUNT_SHIFT); + clrsetbits_le32(&val, UTMIP_XTAL_FREQ_COUNT_MASK, + timing[PARAM_XTAL_FREQ_COUNT] << + UTMIP_XTAL_FREQ_COUNT_SHIFT); + writel(val, &clkrst->crc_utmip_pll_cfg1); + + /* Disable Power Down state for PLL */ + clrbits_le32(&clkrst->crc_utmip_pll_cfg1, + PLLU_POWERDOWN | PLL_ENABLE_POWERDOWN | + PLL_ACTIVE_POWERDOWN); + + /* Recommended PHY settings for EYE diagram */ + val = readl(&usbctlr->utmip_xcvr_cfg0); + clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MASK, + 0x4 << UTMIP_XCVR_SETUP_SHIFT); + clrsetbits_le32(&val, UTMIP_XCVR_SETUP_MSB_MASK, + 0x3 << UTMIP_XCVR_SETUP_MSB_SHIFT); + clrsetbits_le32(&val, UTMIP_XCVR_HSSLEW_MSB_MASK, + 0x8 << UTMIP_XCVR_HSSLEW_MSB_SHIFT); + writel(val, &usbctlr->utmip_xcvr_cfg0); + clrsetbits_le32(&usbctlr->utmip_xcvr_cfg1, + UTMIP_XCVR_TERM_RANGE_ADJ_MASK, + 0x7 << UTMIP_XCVR_TERM_RANGE_ADJ_SHIFT); + + /* Some registers can be controlled from USB1 only. */ + if (config->periph_id != PERIPH_ID_USBD) { + clock_enable(PERIPH_ID_USBD); + /* Disable Reset if in Reset state */ + reset_set_enable(PERIPH_ID_USBD, 0); + } + usb1ctlr = (struct usb_ctlr *) + ((u32)config->reg & USB1_ADDR_MASK); + val = readl(&usb1ctlr->utmip_bias_cfg0); + setbits_le32(&val, UTMIP_HSDISCON_LEVEL_MSB); + clrsetbits_le32(&val, UTMIP_HSDISCON_LEVEL_MASK, + 0x1 << UTMIP_HSDISCON_LEVEL_SHIFT); + clrsetbits_le32(&val, UTMIP_HSSQUELCH_LEVEL_MASK, + 0x2 << UTMIP_HSSQUELCH_LEVEL_SHIFT); + writel(val, &usb1ctlr->utmip_bias_cfg0); + + /* Miscellaneous setting mentioned in Programming Guide */ + clrbits_le32(&usbctlr->utmip_misc_cfg0, + UTMIP_SUSPEND_EXIT_ON_EDGE); + } /* Setting the tracking length time */ clrsetbits_le32(&usbctlr->utmip_bias_cfg1, @@ -308,6 +473,14 @@ static int init_utmi_usb_controller(struct fdt_usb *config) /* Resuscitate crystal clock by setting UTMIP_PHY_XTAL_CLOCKEN */ setbits_le32(&usbctlr->utmip_misc_cfg1, UTMIP_PHY_XTAL_CLOCKEN); + if (controller->has_hostpc) { + if (config->periph_id == PERIPH_ID_USBD) + clrbits_le32(&clkrst->crc_utmip_pll_cfg2, + UTMIP_FORCE_PD_SAMP_A_POWERDOWN); + if (config->periph_id == PERIPH_ID_USB3) + clrbits_le32(&clkrst->crc_utmip_pll_cfg2, + UTMIP_FORCE_PD_SAMP_C_POWERDOWN); + } /* Finished the per-controller init. */ /* De-assert UTMIP_RESET to bring out of reset. */ @@ -336,6 +509,18 @@ static int init_utmi_usb_controller(struct fdt_usb *config) clrbits_le32(&usbctlr->utmip_xcvr_cfg1, UTMIP_FORCE_PDDISC_POWERDOWN | UTMIP_FORCE_PDCHRP_POWERDOWN | UTMIP_FORCE_PDDR_POWERDOWN); + if (controller->has_hostpc) { + /* + * BIAS Pad Power Down is common among all 3 USB + * controllers and can be controlled from USB1 only. + */ + usb1ctlr = (struct usb_ctlr *) + ((u32)config->reg & USB1_ADDR_MASK); + clrbits_le32(&usb1ctlr->utmip_bias_cfg0, UTMIP_BIASPD); + udelay(25); + clrbits_le32(&usb1ctlr->utmip_bias_cfg1, + UTMIP_FORCE_PDTRK_POWERDOWN); + } return 0; } @@ -438,7 +623,7 @@ static void config_clock(const u32 timing[]) timing[PARAM_CPCON], timing[PARAM_LFCON]); } -int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config) +static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config) { const char *phy, *mode; @@ -466,6 +651,8 @@ int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config) config->enabled = fdtdec_get_is_enabled(blob, node); config->has_legacy_mode = fdtdec_get_bool(blob, node, "nvidia,has-legacy-mode"); + if (config->has_legacy_mode) + port_addr_clear_csc = (u32) config->reg; config->periph_id = clock_decode_periph_id(blob, node); if (config->periph_id == PERIPH_ID_NONE) { debug("%s: Missing/invalid peripheral ID\n", __func__); @@ -483,20 +670,22 @@ int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config) return 0; } -int board_usb_init(const void *blob) +/* + * process_usb_nodes() - Process a list of USB nodes, adding them to our list + * of USB ports. + * @blob: fdt blob + * @node_list: list of nodes to process (any <=0 are ignored) + * @count: number of nodes to process + * + * Return: 0 - ok, -1 - error + */ +static int process_usb_nodes(const void *blob, int node_list[], int count) { struct fdt_usb config; - enum clock_osc_freq freq; - int node_list[USB_PORTS_MAX]; - int node, count, i; - - /* Set up the USB clocks correctly based on our oscillator frequency */ - freq = clock_get_osc_freq(); - config_clock(usb_pll[freq]); + int node, i; + int clk_done = 0; - /* count may return <0 on error */ - count = fdtdec_find_aliases_for_id(blob, "usb", - COMPAT_NVIDIA_TEGRA20_USB, node_list, USB_PORTS_MAX); + port_count = 0; for (i = 0; i < count; i++) { if (port_count == USB_PORTS_MAX) { printf("tegrausb: Cannot register more than %d ports\n", @@ -513,6 +702,10 @@ int board_usb_init(const void *blob) fdt_get_name(blob, node, NULL)); return -1; } + if (!clk_done) { + config_clock(get_pll_timing()); + clk_done = 1; + } config.initialized = 0; /* add new USB port to the list of available ports */ @@ -522,6 +715,31 @@ int board_usb_init(const void *blob) return 0; } +int board_usb_init(const void *blob) +{ + int node_list[USB_PORTS_MAX]; + int count, err = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(fdt_usb_controllers); i++) { + controller = &fdt_usb_controllers[i]; + + count = fdtdec_find_aliases_for_id(blob, "usb", + controller->compat, node_list, USB_PORTS_MAX); + if (count) { + err = process_usb_nodes(blob, node_list, count); + if (err) + printf("%s: Error processing USB node!\n", + __func__); + return err; + } + } + if (i == ARRAY_SIZE(fdt_usb_controllers)) + controller = NULL; + + return err; +} + /** * Start up the given port number (ports are numbered from 0 on each board). * This returns values for the appropriate hccr and hcor addresses to use for @@ -564,6 +782,20 @@ success: usbctlr = config->reg; *hccr = (struct ehci_hccr *)&usbctlr->cap_length; *hcor = (struct ehci_hcor *)&usbctlr->usb_cmd; + + if (controller->has_hostpc) { + /* Set to Host mode after Controller Reset was done */ + clrsetbits_le32(&usbctlr->usb_mode, USBMODE_CM_HC, + USBMODE_CM_HC); + /* Select UTMI parallel interface after setting host mode */ + if (config->utmi) { + clrsetbits_le32((char *)&usbctlr->usb_cmd + + HOSTPC1_DEVLC, PTS_MASK, + PTS_UTMI << PTS_SHIFT); + clrbits_le32((char *)&usbctlr->usb_cmd + + HOSTPC1_DEVLC, STS); + } + } return 0; } -- cgit From 3104ce1f6f2d541e8bf2edfb698d0f51dc43b5fb Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 11 Jul 2013 17:23:26 +0200 Subject: net: fec: Remove bogus flush_dcache_range() call Remove incorrectly called and duplicate flush_dcache_range() call from fec_mxc driver. The call is not needed, since the caches are already flushed in fec_tbd_init(), moreover the second argument should be the ending address, not size. Signed-off-by: Marek Vasut Reported-by: Albert Aribaud Cc: Stefano Babic Cc: Tom Rini --- drivers/net/fec_mxc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index da95e285b7..97bf8fe17d 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -560,7 +560,6 @@ static int fec_init(struct eth_device *dev, bd_t* bd) } memset(fec->tbd_base, 0, size); fec_tbd_init(fec); - flush_dcache_range((unsigned)fec->tbd_base, size); } /* -- cgit From ab94cd491faf3e7b0a3b934f5817b15997bcb315 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Fri, 12 Jul 2013 01:03:04 +0200 Subject: net: fec: Avoid MX28 bus sync issue The MX28 multi-layer AHB bus can be too slow and trigger the FEC DMA too early, before all the data hit the DRAM. This patch ensures the data are written in the RAM before the DMA starts. Please see the comment in the patch for full details. This patch was produced with an amazing help from Albert Aribaud, who pointed out it can possibly be such a bus synchronisation issue. Signed-off-by: Marek Vasut Cc: Albert ARIBAUD Cc: Fabio Estevam Cc: Stefano Babic Tested-by: Fabio Estevam Tested-by: Alexandre Pereira da Silva --- drivers/net/fec_mxc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/net/fec_mxc.c b/drivers/net/fec_mxc.c index 97bf8fe17d..ec5b9db660 100644 --- a/drivers/net/fec_mxc.c +++ b/drivers/net/fec_mxc.c @@ -736,6 +736,28 @@ static int fec_send(struct eth_device *dev, void *packet, int length) addr = (uint32_t)fec->tbd_base; flush_dcache_range(addr, addr + size); + /* + * Below we read the DMA descriptor's last four bytes back from the + * DRAM. This is important in order to make sure that all WRITE + * operations on the bus that were triggered by previous cache FLUSH + * have completed. + * + * Otherwise, on MX28, it is possible to observe a corruption of the + * DMA descriptors. Please refer to schematic "Figure 1-2" in MX28RM + * for the bus structure of MX28. The scenario is as follows: + * + * 1) ARM core triggers a series of WRITEs on the AHB_ARB2 bus going + * to DRAM due to flush_dcache_range() + * 2) ARM core writes the FEC registers via AHB_ARB2 + * 3) FEC DMA starts reading/writing from/to DRAM via AHB_ARB3 + * + * Note that 2) does sometimes finish before 1) due to reordering of + * WRITE accesses on the AHB bus, therefore triggering 3) before the + * DMA descriptor is fully written into DRAM. This results in occasional + * corruption of the DMA descriptor. + */ + readl(addr + size - 4); + /* * Enable SmartDMA transmit task */ -- cgit