diff options
Diffstat (limited to 'drivers')
26 files changed, 956 insertions, 273 deletions
diff --git a/drivers/ddr/fsl/ctrl_regs.c b/drivers/ddr/fsl/ctrl_regs.c index 78e82bb..dcf6287 100644 --- a/drivers/ddr/fsl/ctrl_regs.c +++ b/drivers/ddr/fsl/ctrl_regs.c @@ -2304,5 +2304,10 @@ compute_fsl_memctl_config_regs(const memctl_options_t *popts, ddr->debug[2] = 0x00000400; ddr->debug[4] = 0xff800000; #endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A004508 + if ((ip_rev >= 0x40000) && (ip_rev < 0x40400)) + ddr->debug[2] |= 0x00000200; /* set bit 22 */ +#endif + return check_fsl_memctl_config_regs(ddr); } diff --git a/drivers/ddr/fsl/interactive.c b/drivers/ddr/fsl/interactive.c index c9f8630..7fb4187 100644 --- a/drivers/ddr/fsl/interactive.c +++ b/drivers/ddr/fsl/interactive.c @@ -1579,7 +1579,7 @@ void ddr4_spd_dump(const struct ddr4_spd_eeprom_s *spd) printf("%-3d-%3d: ", 128, 255); for (i = 128; i <= 255; i++) - printf("%02x", spd->mod_section.uc[i - 60]); + printf("%02x", spd->mod_section.uc[i - 128]); break; } diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c index eb4e2be..5bf36a0 100644 --- a/drivers/mmc/dw_mmc.c +++ b/drivers/mmc/dw_mmc.c @@ -284,8 +284,8 @@ static int dwmci_setup_bus(struct dwmci_host *host, u32 freq) static void dwmci_set_ios(struct mmc *mmc) { - struct dwmci_host *host = mmc->priv; - u32 ctype; + struct dwmci_host *host = (struct dwmci_host *)mmc->priv; + u32 ctype, regs; debug("Buswidth = %d, clock: %d\n",mmc->bus_width, mmc->clock); @@ -304,6 +304,14 @@ static void dwmci_set_ios(struct mmc *mmc) dwmci_writel(host, DWMCI_CTYPE, ctype); + regs = dwmci_readl(host, DWMCI_UHS_REG); + if (mmc->card_caps & MMC_MODE_DDR_52MHz) + regs |= DWMCI_DDR_MODE; + else + regs &= DWMCI_DDR_MODE; + + dwmci_writel(host, DWMCI_UHS_REG, regs); + if (host->clksel) host->clksel(host); } diff --git a/drivers/mmc/exynos_dw_mmc.c b/drivers/mmc/exynos_dw_mmc.c index de8cdcc..d96dfe1 100644 --- a/drivers/mmc/exynos_dw_mmc.c +++ b/drivers/mmc/exynos_dw_mmc.c @@ -13,6 +13,8 @@ #include <asm/arch/dwmmc.h> #include <asm/arch/clk.h> #include <asm/arch/pinmux.h> +#include <asm/gpio.h> +#include <asm-generic/errno.h> #define DWMMC_MAX_CH_NUM 4 #define DWMMC_MAX_FREQ 52000000 @@ -44,7 +46,11 @@ unsigned int exynos_dwmci_get_clk(struct dwmci_host *host) & DWMCI_DIVRATIO_MASK) + 1; sclk = get_mmc_clk(host->dev_index); - return sclk / clk_div; + /* + * Assume to know divider value. + * When clock unit is broken, need to set "host->div" + */ + return sclk / clk_div / (host->div + 1); } static void exynos_dwmci_board_init(struct dwmci_host *host) @@ -60,48 +66,36 @@ static void exynos_dwmci_board_init(struct dwmci_host *host) } } -/* - * This function adds the mmc channel to be registered with mmc core. - * index - mmc channel number. - * regbase - register base address of mmc channel specified in 'index'. - * bus_width - operating bus width of mmc channel specified in 'index'. - * clksel - value to be written into CLKSEL register in case of FDT. - * NULL in case od non-FDT. - */ -int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel) +static int exynos_dwmci_core_init(struct dwmci_host *host, int index) { - struct dwmci_host *host = NULL; unsigned int div; unsigned long freq, sclk; - host = malloc(sizeof(struct dwmci_host)); - if (!host) { - printf("dwmci_host malloc fail!\n"); - return 1; - } + + if (host->bus_hz) + freq = host->bus_hz; + else + freq = DWMMC_MAX_FREQ; + /* request mmc clock vlaue of 52MHz. */ - freq = 52000000; sclk = get_mmc_clk(index); div = DIV_ROUND_UP(sclk, freq); /* set the clock divisor for mmc */ set_mmc_clk(index, div); host->name = "EXYNOS DWMMC"; - host->ioaddr = (void *)regbase; - host->buswidth = bus_width; #ifdef CONFIG_EXYNOS5420 host->quirks = DWMCI_QUIRK_DISABLE_SMU; #endif host->board_init = exynos_dwmci_board_init; - if (clksel) { - host->clksel_val = clksel; - } else { - if (0 == index) + if (!host->clksel_val) { + if (index == 0) host->clksel_val = DWMMC_MMC0_CLKSEL_VAL; - if (2 == index) + else if (index == 2) host->clksel_val = DWMMC_MMC2_CLKSEL_VAL; } + host->caps = MMC_MODE_DDR_52MHz; host->clksel = exynos_dwmci_clksel; host->dev_index = index; host->get_mmc_clk = exynos_dwmci_get_clk; @@ -113,69 +107,134 @@ int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel) return 0; } +/* + * This function adds the mmc channel to be registered with mmc core. + * index - mmc channel number. + * regbase - register base address of mmc channel specified in 'index'. + * bus_width - operating bus width of mmc channel specified in 'index'. + * clksel - value to be written into CLKSEL register in case of FDT. + * NULL in case od non-FDT. + */ +int exynos_dwmci_add_port(int index, u32 regbase, int bus_width, u32 clksel) +{ + struct dwmci_host *host = NULL; + + host = malloc(sizeof(struct dwmci_host)); + if (!host) { + error("dwmci_host malloc fail!\n"); + return -ENOMEM; + } + + host->ioaddr = (void *)regbase; + host->buswidth = bus_width; + + if (clksel) + host->clksel_val = clksel; + + return exynos_dwmci_core_init(host, index); +} + #ifdef CONFIG_OF_CONTROL -int exynos_dwmmc_init(const void *blob) +static struct dwmci_host dwmci_host[DWMMC_MAX_CH_NUM]; + +static int do_dwmci_init(struct dwmci_host *host) { - int index, bus_width; - int node_list[DWMMC_MAX_CH_NUM]; - int err = 0, dev_id, flag, count, i; - u32 clksel_val, base, timing[3]; + int index, flag, err; - count = fdtdec_find_aliases_for_id(blob, "mmc", - COMPAT_SAMSUNG_EXYNOS5_DWMMC, node_list, - DWMMC_MAX_CH_NUM); + index = host->dev_index; - for (i = 0; i < count; i++) { - int node = node_list[i]; + flag = host->buswidth == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE; + err = exynos_pinmux_config(host->dev_id, flag); + if (err) { + debug("DWMMC not configure\n"); + return err; + } - if (node <= 0) - continue; + return exynos_dwmci_core_init(host, index); +} - /* Extract device id for each mmc channel */ - dev_id = pinmux_decode_periph_id(blob, node); +static int exynos_dwmci_get_config(const void *blob, int node, + struct dwmci_host *host) +{ + int err = 0; + u32 base, clksel_val, timing[3]; - /* Get the bus width from the device node */ - bus_width = fdtdec_get_int(blob, node, "samsung,bus-width", 0); - if (bus_width <= 0) { - debug("DWMMC: Can't get bus-width\n"); - return -1; - } - if (8 == bus_width) - flag = PINMUX_FLAG_8BIT_MODE; - else - flag = PINMUX_FLAG_NONE; + /* Extract device id for each mmc channel */ + host->dev_id = pinmux_decode_periph_id(blob, node); - /* config pinmux for each mmc channel */ - err = exynos_pinmux_config(dev_id, flag); - if (err) { - debug("DWMMC not configured\n"); - return err; - } + /* Get the bus width from the device node */ + host->buswidth = fdtdec_get_int(blob, node, "samsung,bus-width", 0); + if (host->buswidth <= 0) { + debug("DWMMC: Can't get bus-width\n"); + return -EINVAL; + } - index = dev_id - PERIPH_ID_SDMMC0; + host->dev_index = fdtdec_get_int(blob, node, "index", host->dev_id); + if (host->dev_index == host->dev_id) + host->dev_index = host->dev_id - PERIPH_ID_SDMMC0; - /* Get the base address from the device node */ - base = fdtdec_get_addr(blob, node, "reg"); - if (!base) { - debug("DWMMC: Can't get base address\n"); - return -1; - } - /* Extract the timing info from the node */ - err = fdtdec_get_int_array(blob, node, "samsung,timing", - timing, 3); + /* Set the base address from the device node */ + base = fdtdec_get_addr(blob, node, "reg"); + if (!base) { + debug("DWMMC: Can't get base address\n"); + return -EINVAL; + } + host->ioaddr = (void *)base; + + /* Extract the timing info from the node */ + err = fdtdec_get_int_array(blob, node, "samsung,timing", timing, 3); + if (err) { + debug("Can't get sdr-timings for devider\n"); + return -EINVAL; + } + + clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) | + DWMCI_SET_DRV_CLK(timing[1]) | + DWMCI_SET_DIV_RATIO(timing[2])); + if (clksel_val) + host->clksel_val = clksel_val; + + host->fifoth_val = fdtdec_get_int(blob, node, "fifoth_val", 0); + host->bus_hz = fdtdec_get_int(blob, node, "bus_hz", 0); + host->div = fdtdec_get_int(blob, node, "div", 0); + + return 0; +} + +static int exynos_dwmci_process_node(const void *blob, + int node_list[], int count) +{ + struct dwmci_host *host; + int i, node, err; + + for (i = 0; i < count; i++) { + node = node_list[i]; + if (node <= 0) + continue; + host = &dwmci_host[i]; + err = exynos_dwmci_get_config(blob, node, host); if (err) { - debug("Can't get sdr-timings for divider\n"); - return -1; + debug("%s: failed to decode dev %d\n", __func__, i); + return err; } - clksel_val = (DWMCI_SET_SAMPLE_CLK(timing[0]) | - DWMCI_SET_DRV_CLK(timing[1]) | - DWMCI_SET_DIV_RATIO(timing[2])); - /* Initialise each mmc channel */ - err = exynos_dwmci_add_port(index, base, bus_width, clksel_val); - if (err) - debug("dwmmc Channel-%d init failed\n", index); + do_dwmci_init(host); } return 0; } + +int exynos_dwmmc_init(const void *blob) +{ + int compat_id; + int node_list[DWMMC_MAX_CH_NUM]; + int err = 0, count; + + compat_id = COMPAT_SAMSUNG_EXYNOS_DWMMC; + + count = fdtdec_find_aliases_for_id(blob, "mmc", + compat_id, node_list, DWMMC_MAX_CH_NUM); + err = exynos_dwmci_process_node(blob, node_list, count); + + return err; +} #endif diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 8b53ead..55c2c68 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -160,6 +160,9 @@ int mmc_set_blocklen(struct mmc *mmc, int len) { struct mmc_cmd cmd; + if (mmc->card_caps & MMC_MODE_DDR_52MHz) + return 0; + cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = len; @@ -516,10 +519,13 @@ static int mmc_change_freq(struct mmc *mmc) return 0; /* High Speed is set, there are two types: 52MHz and 26MHz */ - if (cardtype & MMC_HS_52MHZ) + if (cardtype & EXT_CSD_CARD_TYPE_52) { + if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) + mmc->card_caps |= MMC_MODE_DDR_52MHz; mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; - else + } else { mmc->card_caps |= MMC_MODE_HS; + } return 0; } @@ -1082,6 +1088,8 @@ static int mmc_startup(struct mmc *mmc) /* An array of possible bus widths in order of preference */ static unsigned ext_csd_bits[] = { + EXT_CSD_DDR_BUS_WIDTH_8, + EXT_CSD_DDR_BUS_WIDTH_4, EXT_CSD_BUS_WIDTH_8, EXT_CSD_BUS_WIDTH_4, EXT_CSD_BUS_WIDTH_1, @@ -1089,13 +1097,15 @@ static int mmc_startup(struct mmc *mmc) /* An array to map CSD bus widths to host cap bits */ static unsigned ext_to_hostcaps[] = { + [EXT_CSD_DDR_BUS_WIDTH_4] = MMC_MODE_DDR_52MHz, + [EXT_CSD_DDR_BUS_WIDTH_8] = MMC_MODE_DDR_52MHz, [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, }; /* An array to map chosen bus width to an integer */ static unsigned widths[] = { - 8, 4, 1, + 8, 4, 8, 4, 1, }; for (idx=0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c index ccae4cc..2ff0ec2 100644 --- a/drivers/mmc/s5p_sdhci.c +++ b/drivers/mmc/s5p_sdhci.c @@ -65,17 +65,9 @@ static void s5p_sdhci_set_control_reg(struct sdhci_host *host) sdhci_writel(host, ctrl, SDHCI_CONTROL2); } -int s5p_sdhci_init(u32 regbase, int index, int bus_width) +static int s5p_sdhci_core_init(struct sdhci_host *host) { - struct sdhci_host *host = NULL; - host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); - if (!host) { - printf("sdhci__host malloc fail!\n"); - return 1; - } - host->name = S5P_NAME; - host->ioaddr = (void *)regbase; host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | @@ -85,15 +77,28 @@ int s5p_sdhci_init(u32 regbase, int index, int bus_width) host->set_control_reg = &s5p_sdhci_set_control_reg; host->set_clock = set_mmc_clk; - host->index = index; host->host_caps = MMC_MODE_HC; - if (bus_width == 8) + if (host->bus_width == 8) host->host_caps |= MMC_MODE_8BIT; return add_sdhci(host, 52000000, 400000); } +int s5p_sdhci_init(u32 regbase, int index, int bus_width) +{ + struct sdhci_host *host = malloc(sizeof(struct sdhci_host)); + if (!host) { + printf("sdhci__host malloc fail!\n"); + return 1; + } + host->ioaddr = (void *)regbase; + host->index = index; + host->bus_width = bus_width; + + return s5p_sdhci_core_init(host); +} + #ifdef CONFIG_OF_CONTROL struct sdhci_host sdhci_host[SDHCI_MAX_HOSTS]; @@ -126,20 +131,7 @@ static int do_sdhci_init(struct sdhci_host *host) } } - host->name = S5P_NAME; - - host->quirks = SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_BROKEN_VOLTAGE | - SDHCI_QUIRK_BROKEN_R1B | SDHCI_QUIRK_32BIT_DMA_ADDR | - SDHCI_QUIRK_WAIT_SEND_CMD; - host->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; - host->version = sdhci_readw(host, SDHCI_HOST_VERSION); - - host->set_control_reg = &s5p_sdhci_set_control_reg; - host->set_clock = set_mmc_clk; - - host->host_caps = MMC_MODE_HC; - - return add_sdhci(host, 52000000, 400000); + return s5p_sdhci_core_init(host); } static int sdhci_get_config(const void *blob, int node, struct sdhci_host *host) diff --git a/drivers/mtd/nand/am335x_spl_bch.c b/drivers/mtd/nand/am335x_spl_bch.c index bd89b06..ce65d8e 100644 --- a/drivers/mtd/nand/am335x_spl_bch.c +++ b/drivers/mtd/nand/am335x_spl_bch.c @@ -55,7 +55,7 @@ static int nand_command(int block, int page, uint32_t offs, } /* Shift the offset from byte addressing to word addressing. */ - if (this->options & NAND_BUSWIDTH_16) + if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) offs >>= 1; /* Set ALE and clear CLE to start address cycle */ diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index e1fc48f..e73834d 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1195,7 +1195,7 @@ static int nand_command(int block, int page, uint32_t offs, u8 cmd) hwctrl(&mtd, cmd, NAND_CTRL_CLE | NAND_CTRL_CHANGE); - if (this->options & NAND_BUSWIDTH_16) + if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) offs >>= 1; hwctrl(&mtd, offs & 0xff, NAND_CTRL_ALE | NAND_CTRL_CHANGE); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 1ce55fd..376976d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -575,7 +575,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) + if ((chip->options & NAND_BUSWIDTH_16) && + !nand_opcode_8bits(command)) column >>= 1; chip->cmd_ctrl(mtd, column, ctrl); ctrl &= ~NAND_CTRL_CHANGE; @@ -668,7 +669,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, /* Serially input address */ if (column != -1) { /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) + if ((chip->options & NAND_BUSWIDTH_16) && + !nand_opcode_8bits(command)) column >>= 1; chip->cmd_ctrl(mtd, column, ctrl); ctrl &= ~NAND_CTRL_CHANGE; @@ -2582,7 +2584,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int *busw) { struct nand_onfi_params *p = &chip->onfi_params; - int i; + int i, j; int val; /* Try ONFI for unknown chip or LP */ @@ -2593,7 +2595,8 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); for (i = 0; i < 3; i++) { - chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); + for (j = 0; j < sizeof(*p); j++) + ((uint8_t *)p)[j] = chip->read_byte(mtd); if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == le16_to_cpu(p->crc)) { pr_info("ONFI param page %d valid\n", i); diff --git a/drivers/mtd/nand/nand_spl_simple.c b/drivers/mtd/nand/nand_spl_simple.c index cead4b5..700ca32 100644 --- a/drivers/mtd/nand/nand_spl_simple.c +++ b/drivers/mtd/nand/nand_spl_simple.c @@ -78,7 +78,7 @@ static int nand_command(int block, int page, uint32_t offs, } /* Shift the offset from byte addressing to word addressing. */ - if (this->options & NAND_BUSWIDTH_16) + if ((this->options & NAND_BUSWIDTH_16) && !nand_opcode_8bits(cmd)) offs >>= 1; /* Begin command latch cycle */ diff --git a/drivers/mtd/nand/omap_elm.c b/drivers/mtd/nand/omap_elm.c index 47b1f1b..d963e6c 100644 --- a/drivers/mtd/nand/omap_elm.c +++ b/drivers/mtd/nand/omap_elm.c @@ -16,23 +16,21 @@ #include <common.h> #include <asm/io.h> #include <asm/errno.h> -#include <linux/mtd/omap_gpmc.h> #include <linux/mtd/omap_elm.h> #include <asm/arch/hardware.h> +#define DRIVER_NAME "omap-elm" #define ELM_DEFAULT_POLY (0) struct elm *elm_cfg; /** - * elm_load_syndromes - Load BCH syndromes based on nibble selection + * elm_load_syndromes - Load BCH syndromes based on bch_type selection * @syndrome: BCH syndrome - * @nibbles: + * @bch_type: BCH4/BCH8/BCH16 * @poly: Syndrome Polynomial set to use - * - * Load BCH syndromes based on nibble selection */ -static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) +static void elm_load_syndromes(u8 *syndrome, enum bch_level bch_type, u8 poly) { u32 *ptr; u32 val; @@ -48,8 +46,7 @@ static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) (syndrome[7] << 24); writel(val, ptr); - /* BCH 8-bit with 26 nibbles (4*8=32) */ - if (nibbles > 13) { + if (bch_type == BCH_8_BIT || bch_type == BCH_16_BIT) { /* reg 2 */ ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[2]; val = syndrome[8] | (syndrome[9] << 8) | (syndrome[10] << 16) | @@ -62,8 +59,7 @@ static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) writel(val, ptr); } - /* BCH 16-bit with 52 nibbles (7*8=56) */ - if (nibbles > 26) { + if (bch_type == BCH_16_BIT) { /* reg 4 */ ptr = &elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[4]; val = syndrome[16] | (syndrome[17] << 8) | @@ -87,7 +83,7 @@ static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) /** * elm_check_errors - Check for BCH errors and return error locations * @syndrome: BCH syndrome - * @nibbles: + * @bch_type: BCH4/BCH8/BCH16 * @error_count: Returns number of errrors in the syndrome * @error_locations: Returns error locations (in decimal) in this array * @@ -95,14 +91,14 @@ static void elm_load_syndromes(u8 *syndrome, u32 nibbles, u8 poly) * and locations in the array passed. Returns -1 if error is not correctable, * else returns 0 */ -int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count, +int elm_check_error(u8 *syndrome, enum bch_level bch_type, u32 *error_count, u32 *error_locations) { u8 poly = ELM_DEFAULT_POLY; s8 i; u32 location_status; - elm_load_syndromes(syndrome, nibbles, poly); + elm_load_syndromes(syndrome, bch_type, poly); /* start processing */ writel((readl(&elm_cfg->syndrome_fragments[poly].syndrome_fragment_x[6]) @@ -118,8 +114,10 @@ int elm_check_error(u8 *syndrome, u32 nibbles, u32 *error_count, /* check if correctable */ location_status = readl(&elm_cfg->error_location[poly].location_status); - if (!(location_status & ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK)) - return -1; + if (!(location_status & ELM_LOCATION_STATUS_ECC_CORRECTABLE_MASK)) { + printf("%s: uncorrectable ECC errors\n", DRIVER_NAME); + return -EBADMSG; + } /* get error count */ *error_count = readl(&elm_cfg->error_location[poly].location_status) & diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index bf99b8e..1acf06b 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -148,35 +148,20 @@ static int __maybe_unused omap_correct_data(struct mtd_info *mtd, uint8_t *dat, } /* - * Generic BCH interface + * Driver configurations */ -struct nand_bch_priv { - uint8_t mode; - uint8_t type; - uint8_t nibbles; +struct omap_nand_info { struct bch_control *control; enum omap_ecc ecc_scheme; }; -/* bch types */ -#define ECC_BCH4 0 -#define ECC_BCH8 1 -#define ECC_BCH16 2 - -/* BCH nibbles for diff bch levels */ -#define ECC_BCH4_NIBBLES 13 -#define ECC_BCH8_NIBBLES 26 -#define ECC_BCH16_NIBBLES 52 - /* * This can be a single instance cause all current users have only one NAND * with nearly the same setup (BCH8, some with ELM and others with sw BCH * library). * When some users with other BCH strength will exists this have to change! */ -static __maybe_unused struct nand_bch_priv bch_priv = { - .type = ECC_BCH8, - .nibbles = ECC_BCH8_NIBBLES, +static __maybe_unused struct omap_nand_info omap_nand_info = { .control = NULL }; @@ -206,7 +191,7 @@ __maybe_unused static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) { struct nand_chip *nand = mtd->priv; - struct nand_bch_priv *bch = nand->priv; + struct omap_nand_info *info = nand->priv; unsigned int dev_width = (nand->options & NAND_BUSWIDTH_16) ? 1 : 0; unsigned int ecc_algo = 0; unsigned int bch_type = 0; @@ -215,7 +200,7 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) u32 ecc_config_val = 0; /* configure GPMC for specific ecc-scheme */ - switch (bch->ecc_scheme) { + switch (info->ecc_scheme) { case OMAP_ECC_HAM1_CODE_SW: return; case OMAP_ECC_HAM1_CODE_HW: @@ -239,6 +224,19 @@ static void omap_enable_hwecc(struct mtd_info *mtd, int32_t mode) eccsize1 = 2; /* non-ECC bits in nibbles per sector */ } break; + case OMAP_ECC_BCH16_CODE_HW: + ecc_algo = 0x1; + bch_type = 0x2; + if (mode == NAND_ECC_WRITE) { + bch_wrapmode = 0x01; + eccsize0 = 0; /* extra bits in nibbles per sector */ + eccsize1 = 52; /* OOB bits in nibbles per sector */ + } else { + bch_wrapmode = 0x01; + eccsize0 = 52; /* ECC bits in nibbles per sector */ + eccsize1 = 0; /* non-ECC bits in nibbles per sector */ + } + break; default: return; } @@ -277,11 +275,11 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code) { struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *bch = chip->priv; + struct omap_nand_info *info = chip->priv; uint32_t *ptr, val = 0; int8_t i = 0, j; - switch (bch->ecc_scheme) { + switch (info->ecc_scheme) { case OMAP_ECC_HAM1_CODE_HW: val = readl(&gpmc_cfg->ecc1_result); ecc_code[0] = val & 0xFF; @@ -305,11 +303,34 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, ptr--; } break; + case OMAP_ECC_BCH16_CODE_HW: + val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[2]); + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[1]); + ecc_code[i++] = (val >> 24) & 0xFF; + ecc_code[i++] = (val >> 16) & 0xFF; + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + val = readl(&gpmc_cfg->bch_result_4_6[0].bch_result_x[0]); + ecc_code[i++] = (val >> 24) & 0xFF; + ecc_code[i++] = (val >> 16) & 0xFF; + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + for (j = 3; j >= 0; j--) { + val = readl(&gpmc_cfg->bch_result_0_3[0].bch_result_x[j] + ); + ecc_code[i++] = (val >> 24) & 0xFF; + ecc_code[i++] = (val >> 16) & 0xFF; + ecc_code[i++] = (val >> 8) & 0xFF; + ecc_code[i++] = (val >> 0) & 0xFF; + } + break; default: return -EINVAL; } /* ECC scheme specific syndrome customizations */ - switch (bch->ecc_scheme) { + switch (info->ecc_scheme) { case OMAP_ECC_HAM1_CODE_HW: break; #ifdef CONFIG_BCH @@ -323,6 +344,8 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, case OMAP_ECC_BCH8_CODE_HW: ecc_code[chip->ecc.bytes - 1] = 0x00; break; + case OMAP_ECC_BCH16_CODE_HW: + break; default: return -EINVAL; } @@ -345,16 +368,17 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) { struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *bch = chip->priv; - uint32_t eccbytes = chip->ecc.bytes; + struct omap_nand_info *info = chip->priv; + struct nand_ecc_ctrl *ecc = &chip->ecc; uint32_t error_count = 0, error_max; - uint32_t error_loc[8]; + uint32_t error_loc[ELM_MAX_ERROR_COUNT]; + enum bch_level bch_type; uint32_t i, ecc_flag = 0; uint8_t count, err = 0; uint32_t byte_pos, bit_pos; /* check calculated ecc */ - for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) { + for (i = 0; i < ecc->bytes && !ecc_flag; i++) { if (calc_ecc[i] != 0x00) ecc_flag = 1; } @@ -363,7 +387,7 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, /* check for whether its a erased-page */ ecc_flag = 0; - for (i = 0; i < chip->ecc.bytes && !ecc_flag; i++) { + for (i = 0; i < ecc->bytes && !ecc_flag; i++) { if (read_ecc[i] != 0xff) ecc_flag = 1; } @@ -374,25 +398,33 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, * while reading ECC result we read it in big endian. * Hence while loading to ELM we have rotate to get the right endian. */ - switch (bch->ecc_scheme) { + switch (info->ecc_scheme) { case OMAP_ECC_BCH8_CODE_HW: - omap_reverse_list(calc_ecc, eccbytes - 1); + bch_type = BCH_8_BIT; + omap_reverse_list(calc_ecc, ecc->bytes - 1); + break; + case OMAP_ECC_BCH16_CODE_HW: + bch_type = BCH_16_BIT; + omap_reverse_list(calc_ecc, ecc->bytes); break; default: return -EINVAL; } /* use elm module to check for errors */ - elm_config((enum bch_level)(bch->type)); - if (elm_check_error(calc_ecc, bch->nibbles, &error_count, error_loc)) { - printf("nand: error: uncorrectable ECC errors\n"); - return -EINVAL; - } + elm_config(bch_type); + err = elm_check_error(calc_ecc, bch_type, &error_count, error_loc); + if (err) + return err; + /* correct bch error */ for (count = 0; count < error_count; count++) { - switch (bch->type) { - case ECC_BCH8: + switch (info->ecc_scheme) { + case OMAP_ECC_BCH8_CODE_HW: /* 14th byte in ECC is reserved to match ROM layout */ - error_max = SECTOR_BYTES + (eccbytes - 1); + error_max = SECTOR_BYTES + (ecc->bytes - 1); + break; + case OMAP_ECC_BCH16_CODE_HW: + error_max = SECTOR_BYTES + ecc->bytes; break; default: return -EINVAL; @@ -496,10 +528,10 @@ static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data, /* cannot correct more than 8 errors */ unsigned int errloc[8]; struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *chip_priv = chip->priv; - struct bch_control *bch = chip_priv->control; + struct omap_nand_info *info = chip->priv; - count = decode_bch(bch, NULL, 512, read_ecc, calc_ecc, NULL, errloc); + count = decode_bch(info->control, NULL, 512, read_ecc, calc_ecc, + NULL, errloc); if (count > 0) { /* correct errors */ for (i = 0; i < count; i++) { @@ -535,15 +567,11 @@ static int omap_correct_data_bch_sw(struct mtd_info *mtd, u_char *data, static void __maybe_unused omap_free_bch(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - struct nand_bch_priv *chip_priv = chip->priv; - struct bch_control *bch = NULL; - - if (chip_priv) - bch = chip_priv->control; + struct omap_nand_info *info = chip->priv; - if (bch) { - free_bch(bch); - chip_priv->control = NULL; + if (info->control) { + free_bch(info->control); + info->control = NULL; } } #endif /* CONFIG_BCH */ @@ -557,7 +585,7 @@ static void __maybe_unused omap_free_bch(struct mtd_info *mtd) */ static int omap_select_ecc_scheme(struct nand_chip *nand, enum omap_ecc ecc_scheme, unsigned int pagesize, unsigned int oobsize) { - struct nand_bch_priv *bch = nand->priv; + struct omap_nand_info *info = nand->priv; struct nand_ecclayout *ecclayout = &omap_ecclayout; int eccsteps = pagesize / SECTOR_BYTES; int i; @@ -567,12 +595,10 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, debug("nand: selected OMAP_ECC_HAM1_CODE_SW\n"); /* For this ecc-scheme, ecc.bytes, ecc.layout, ... are * initialized in nand_scan_tail(), so just set ecc.mode */ - bch_priv.control = NULL; - bch_priv.type = 0; + info->control = NULL; nand->ecc.mode = NAND_ECC_SOFT; nand->ecc.layout = NULL; nand->ecc.size = 0; - bch->ecc_scheme = OMAP_ECC_HAM1_CODE_SW; break; case OMAP_ECC_HAM1_CODE_HW: @@ -583,8 +609,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, (3 * eccsteps) + BADBLOCK_MARKER_LENGTH)); return -EINVAL; } - bch_priv.control = NULL; - bch_priv.type = 0; + info->control = NULL; /* populate ecc specific fields */ memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); nand->ecc.mode = NAND_ECC_HW; @@ -605,7 +630,6 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - BADBLOCK_MARKER_LENGTH; - bch->ecc_scheme = OMAP_ECC_HAM1_CODE_HW; break; case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: @@ -618,12 +642,11 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, return -EINVAL; } /* check if BCH S/W library can be used for error detection */ - bch_priv.control = init_bch(13, 8, 0x201b); - if (!bch_priv.control) { + info->control = init_bch(13, 8, 0x201b); + if (!info->control) { printf("nand: error: could not init_bch()\n"); return -ENODEV; } - bch_priv.type = ECC_BCH8; /* populate ecc specific fields */ memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); nand->ecc.mode = NAND_ECC_HW; @@ -647,7 +670,6 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - BADBLOCK_MARKER_LENGTH; - bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW_DETECTION_SW; break; #else printf("nand: error: CONFIG_BCH required for ECC\n"); @@ -665,7 +687,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, } /* intialize ELM for ECC error detection */ elm_init(); - bch_priv.type = ECC_BCH8; + info->control = NULL; /* populate ecc specific fields */ memset(&nand->ecc, 0, sizeof(struct nand_ecc_ctrl)); nand->ecc.mode = NAND_ECC_HW; @@ -683,13 +705,44 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; ecclayout->oobfree[0].length = oobsize - ecclayout->eccbytes - BADBLOCK_MARKER_LENGTH; - bch->ecc_scheme = OMAP_ECC_BCH8_CODE_HW; break; #else printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n"); return -EINVAL; #endif + case OMAP_ECC_BCH16_CODE_HW: +#ifdef CONFIG_NAND_OMAP_ELM + debug("nand: using OMAP_ECC_BCH16_CODE_HW\n"); + /* check ecc-scheme requirements before updating ecc info */ + if ((26 * eccsteps) + BADBLOCK_MARKER_LENGTH > oobsize) { + printf("nand: error: insufficient OOB: require=%d\n", ( + (26 * eccsteps) + BADBLOCK_MARKER_LENGTH)); + return -EINVAL; + } + /* intialize ELM for ECC error detection */ + elm_init(); + /* populate ecc specific fields */ + nand->ecc.mode = NAND_ECC_HW; + nand->ecc.size = SECTOR_BYTES; + nand->ecc.bytes = 26; + nand->ecc.strength = 16; + nand->ecc.hwctl = omap_enable_hwecc; + nand->ecc.correct = omap_correct_data_bch; + nand->ecc.calculate = omap_calculate_ecc; + nand->ecc.read_page = omap_read_page_bch; + /* define ecc-layout */ + ecclayout->eccbytes = nand->ecc.bytes * eccsteps; + for (i = 0; i < ecclayout->eccbytes; i++) + ecclayout->eccpos[i] = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].offset = i + BADBLOCK_MARKER_LENGTH; + ecclayout->oobfree[0].length = oobsize - nand->ecc.bytes - + BADBLOCK_MARKER_LENGTH; + break; +#else + printf("nand: error: CONFIG_NAND_OMAP_ELM required for ECC\n"); + return -EINVAL; +#endif default: debug("nand: error: ecc scheme not enabled or supported\n"); return -EINVAL; @@ -699,6 +752,7 @@ static int omap_select_ecc_scheme(struct nand_chip *nand, if (ecc_scheme != OMAP_ECC_HAM1_CODE_SW) nand->ecc.layout = ecclayout; + info->ecc_scheme = ecc_scheme; return 0; } @@ -802,16 +856,21 @@ int board_nand_init(struct nand_chip *nand) nand->IO_ADDR_R = (void __iomem *)&gpmc_cfg->cs[cs].nand_dat; nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; - nand->priv = &bch_priv; + nand->priv = &omap_nand_info; nand->cmd_ctrl = omap_nand_hwcontrol; nand->options |= NAND_NO_PADDING | NAND_CACHEPRG; - /* If we are 16 bit dev, our gpmc config tells us that */ - if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000) - nand->options |= NAND_BUSWIDTH_16; - nand->chip_delay = 100; nand->ecc.layout = &omap_ecclayout; + /* configure driver and controller based on NAND device bus-width */ + gpmc_config = readl(&gpmc_cfg->cs[cs].config1); +#if defined(CONFIG_SYS_NAND_BUSWIDTH_16BIT) + nand->options |= NAND_BUSWIDTH_16; + writel(gpmc_config | (0x1 << 12), &gpmc_cfg->cs[cs].config1); +#else + nand->options &= ~NAND_BUSWIDTH_16; + writel(gpmc_config & ~(0x1 << 12), &gpmc_cfg->cs[cs].config1); +#endif /* select ECC scheme */ #if defined(CONFIG_NAND_OMAP_ECCSCHEME) err = omap_select_ecc_scheme(nand, CONFIG_NAND_OMAP_ECCSCHEME, diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 230ed97..aac85c4 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -609,10 +609,8 @@ static struct phy_device *create_phy_by_mask(struct mii_dev *bus, while (phy_mask) { int addr = ffs(phy_mask) - 1; int r = get_phy_id(bus, addr, devad, &phy_id); - if (r < 0) - return ERR_PTR(r); /* If the PHY ID is mostly f's, we didn't find anything */ - if ((phy_id & 0x1fffffff) != 0x1fffffff) + if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff) return phy_device_create(bus, addr, phy_id, interface); phy_mask &= ~(1 << addr); } diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 5e132f2..81e8ddb 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -67,7 +67,8 @@ int sh_eth_send(struct eth_device *dev, void *packet, int len) /* packet must be a 4 byte boundary */ if ((int)packet & 3) { - printf(SHETHER_NAME ": %s: packet not 4 byte alligned\n", __func__); + printf(SHETHER_NAME ": %s: packet not 4 byte alligned\n" + , __func__); ret = -EFAULT; goto err; } @@ -148,7 +149,7 @@ int sh_eth_recv(struct eth_device *dev) static int sh_eth_reset(struct sh_eth_dev *eth) { -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) int ret = 0, i; /* Start e-dmac transmitter and receiver */ @@ -156,7 +157,7 @@ static int sh_eth_reset(struct sh_eth_dev *eth) /* Perform a software reset and wait for it to complete */ sh_eth_write(eth, EDMR_SRST, EDMR); - for (i = 0; i < TIMEOUT_CNT ; i++) { + for (i = 0; i < TIMEOUT_CNT; i++) { if (!(sh_eth_read(eth, EDMR) & EDMR_SRST)) break; udelay(1000); @@ -218,7 +219,7 @@ static int sh_eth_tx_desc_init(struct sh_eth_dev *eth) /* Point the controller to the tx descriptor list. Must use physical addresses */ sh_eth_write(eth, ADDR_TO_PHY(port_info->tx_desc_base), TDLAR); -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) sh_eth_write(eth, ADDR_TO_PHY(port_info->tx_desc_base), TDFAR); sh_eth_write(eth, ADDR_TO_PHY(cur_tx_desc), TDFXR); sh_eth_write(eth, 0x01, TDFFR);/* Last discriptor bit */ @@ -288,7 +289,7 @@ static int sh_eth_rx_desc_init(struct sh_eth_dev *eth) /* Point the controller to the rx descriptor list */ sh_eth_write(eth, ADDR_TO_PHY(port_info->rx_desc_base), RDLAR); -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) sh_eth_write(eth, ADDR_TO_PHY(port_info->rx_desc_base), RDFAR); sh_eth_write(eth, ADDR_TO_PHY(cur_rx_desc), RDFXR); sh_eth_write(eth, RDFFR_RDLF, RDFFR); @@ -384,7 +385,7 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) sh_eth_write(eth, 0, TFTR); sh_eth_write(eth, (FIFO_SIZE_T | FIFO_SIZE_R), FDR); sh_eth_write(eth, RMCR_RST, RMCR); -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) sh_eth_write(eth, 0, RPADIR); #endif sh_eth_write(eth, (FIFO_F_D_RFF | FIFO_F_D_RFD), FCFTR); @@ -403,6 +404,8 @@ static int sh_eth_config(struct sh_eth_dev *eth, bd_t *bd) sh_eth_write(eth, RFLR_RFL_MIN, RFLR); #if defined(SH_ETH_TYPE_GETHER) sh_eth_write(eth, 0, PIPR); +#endif +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) sh_eth_write(eth, APR_AP, APR); sh_eth_write(eth, MPR_MP, MPR); sh_eth_write(eth, TPAUSER_TPAUSE, TPAUSER); @@ -521,41 +524,41 @@ void sh_eth_halt(struct eth_device *dev) int sh_eth_initialize(bd_t *bd) { - int ret = 0; + int ret = 0; struct sh_eth_dev *eth = NULL; - struct eth_device *dev = NULL; + struct eth_device *dev = NULL; - eth = (struct sh_eth_dev *)malloc(sizeof(struct sh_eth_dev)); + eth = (struct sh_eth_dev *)malloc(sizeof(struct sh_eth_dev)); if (!eth) { printf(SHETHER_NAME ": %s: malloc failed\n", __func__); ret = -ENOMEM; goto err; } - dev = (struct eth_device *)malloc(sizeof(struct eth_device)); + dev = (struct eth_device *)malloc(sizeof(struct eth_device)); if (!dev) { printf(SHETHER_NAME ": %s: malloc failed\n", __func__); ret = -ENOMEM; goto err; } - memset(dev, 0, sizeof(struct eth_device)); - memset(eth, 0, sizeof(struct sh_eth_dev)); + memset(dev, 0, sizeof(struct eth_device)); + memset(eth, 0, sizeof(struct sh_eth_dev)); eth->port = CONFIG_SH_ETHER_USE_PORT; eth->port_info[eth->port].phy_addr = CONFIG_SH_ETHER_PHY_ADDR; - dev->priv = (void *)eth; - dev->iobase = 0; - dev->init = sh_eth_init; - dev->halt = sh_eth_halt; - dev->send = sh_eth_send; - dev->recv = sh_eth_recv; - eth->port_info[eth->port].dev = dev; + dev->priv = (void *)eth; + dev->iobase = 0; + dev->init = sh_eth_init; + dev->halt = sh_eth_halt; + dev->send = sh_eth_send; + dev->recv = sh_eth_recv; + eth->port_info[eth->port].dev = dev; sprintf(dev->name, SHETHER_NAME); - /* Register Device to EtherNet subsystem */ - eth_register(dev); + /* Register Device to EtherNet subsystem */ + eth_register(dev); bb_miiphy_buses[0].priv = eth; miiphy_register(dev->name, bb_miiphy_read, bb_miiphy_write); diff --git a/drivers/net/sh_eth.h b/drivers/net/sh_eth.h index 331c07c..d0d9aaa 100644 --- a/drivers/net/sh_eth.h +++ b/drivers/net/sh_eth.h @@ -230,6 +230,61 @@ static const u16 sh_eth_offset_gigabit[SH_ETH_MAX_REGISTER_OFFSET] = { [RMII_MII] = 0x0790, }; +#if defined(SH_ETH_TYPE_RZ) +static const u16 sh_eth_offset_rz[SH_ETH_MAX_REGISTER_OFFSET] = { + [EDSR] = 0x0000, + [EDMR] = 0x0400, + [EDTRR] = 0x0408, + [EDRRR] = 0x0410, + [EESR] = 0x0428, + [EESIPR] = 0x0430, + [TDLAR] = 0x0010, + [TDFAR] = 0x0014, + [TDFXR] = 0x0018, + [TDFFR] = 0x001c, + [RDLAR] = 0x0030, + [RDFAR] = 0x0034, + [RDFXR] = 0x0038, + [RDFFR] = 0x003c, + [TRSCER] = 0x0438, + [RMFCR] = 0x0440, + [TFTR] = 0x0448, + [FDR] = 0x0450, + [RMCR] = 0x0458, + [RPADIR] = 0x0460, + [FCFTR] = 0x0468, + [CSMR] = 0x04E4, + + [ECMR] = 0x0500, + [ECSR] = 0x0510, + [ECSIPR] = 0x0518, + [PSR] = 0x0528, + [PIPR] = 0x052c, + [RFLR] = 0x0508, + [APR] = 0x0554, + [MPR] = 0x0558, + [PFTCR] = 0x055c, + [PFRCR] = 0x0560, + [TPAUSER] = 0x0564, + [GECMR] = 0x05b0, + [BCULR] = 0x05b4, + [MAHR] = 0x05c0, + [MALR] = 0x05c8, + [TROCR] = 0x0700, + [CDCR] = 0x0708, + [LCCR] = 0x0710, + [CEFCR] = 0x0740, + [FRECR] = 0x0748, + [TSFRCR] = 0x0750, + [TLFRCR] = 0x0758, + [RFCR] = 0x0760, + [CERCR] = 0x0768, + [CEECR] = 0x0770, + [MAFCR] = 0x0778, + [RMII_MII] = 0x0790, +}; +#endif + static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { [ECMR] = 0x0100, [RFLR] = 0x0108, @@ -306,13 +361,16 @@ static const u16 sh_eth_offset_fast_sh4[SH_ETH_MAX_REGISTER_OFFSET] = { #elif defined(CONFIG_R8A7790) || defined(CONFIG_R8A7791) #define SH_ETH_TYPE_ETHER #define BASE_IO_ADDR 0xEE700200 +#elif defined(CONFIG_R7S72100) +#define SH_ETH_TYPE_RZ +#define BASE_IO_ADDR 0xE8203000 #endif /* * Register's bits * Copy from Linux driver source code */ -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) /* EDSR */ enum EDSR_BIT { EDSR_ENT = 0x01, EDSR_ENR = 0x02, @@ -323,7 +381,7 @@ enum EDSR_BIT { /* EDMR */ enum DMAC_M_BIT { EDMR_DL1 = 0x20, EDMR_DL0 = 0x10, -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) EDMR_SRST = 0x03, /* Receive/Send reset */ EMDR_DESC_R = 0x30, /* Descriptor reserve size */ EDMR_EL = 0x40, /* Litte endian */ @@ -349,7 +407,7 @@ enum DMAC_M_BIT { /* EDTRR */ enum DMAC_T_BIT { -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) EDTRR_TRNS = 0x03, #else EDTRR_TRNS = 0x01, @@ -394,7 +452,6 @@ enum PHY_STATUS_BIT { PHY_ST_LINK = 0x01, }; /* EESR */ enum EESR_BIT { - #if defined(SH_ETH_TYPE_ETHER) EESR_TWB = 0x40000000, #else @@ -419,12 +476,12 @@ enum EESR_BIT { EESR_CD = 0x00000200, EESR_RTO = 0x00000100, EESR_RMAF = 0x00000080, EESR_CEEF = 0x00000040, EESR_CELF = 0x00000020, EESR_RRF = 0x00000010, - rESR_RTLF = 0x00000008, EESR_RTSF = 0x00000004, + EESR_RTLF = 0x00000008, EESR_RTSF = 0x00000004, EESR_PRE = 0x00000002, EESR_CERF = 0x00000001, }; -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) # define TX_CHECK (EESR_TC1 | EESR_FTC) # define EESR_ERR_CHECK (EESR_TWB | EESR_TABT | EESR_RABT | EESR_RDE \ | EESR_RFRMER | EESR_TFE | EESR_TDE | EESR_ECI) @@ -484,7 +541,8 @@ enum FCFTR_BIT { /* Transfer descriptor bit */ enum TD_STS_BIT { -#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_ETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_ETHER) || \ + defined(SH_ETH_TYPE_RZ) TD_TACT = 0x80000000, #else TD_TACT = 0x7fffffff, @@ -500,9 +558,9 @@ enum TD_STS_BIT { enum RECV_RST_BIT { RMCR_RST = 0x01, }; /* ECMR */ enum FELIC_MODE_BIT { -#if defined(SH_ETH_TYPE_GETHER) - ECMR_TRCCM=0x04000000, ECMR_RCSC= 0x00800000, ECMR_DPAD= 0x00200000, - ECMR_RZPF = 0x00100000, +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) + ECMR_TRCCM = 0x04000000, ECMR_RCSC = 0x00800000, + ECMR_DPAD = 0x00200000, ECMR_RZPF = 0x00100000, #endif ECMR_ZPF = 0x00080000, ECMR_PFR = 0x00040000, ECMR_RXF = 0x00020000, ECMR_TXF = 0x00010000, ECMR_MCT = 0x00002000, ECMR_PRCEF = 0x00001000, @@ -517,9 +575,9 @@ enum FELIC_MODE_BIT { }; -#if defined(SH_ETH_TYPE_GETHER) -#define ECMR_CHG_DM (ECMR_TRCCM | ECMR_RZPF | ECMR_ZPF | ECMR_PFR | ECMR_RXF | \ - ECMR_TXF | ECMR_MCT) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) +#define ECMR_CHG_DM (ECMR_TRCCM | ECMR_RZPF | ECMR_ZPF | ECMR_PFR | \ + ECMR_RXF | ECMR_TXF | ECMR_MCT) #elif defined(SH_ETH_TYPE_ETHER) #define ECMR_CHG_DM (ECMR_ZPF | ECMR_PFR | ECMR_RXF | ECMR_TXF) #else @@ -535,7 +593,7 @@ enum ECSR_STATUS_BIT { ECSR_MPD = 0x02, ECSR_ICD = 0x01, }; -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) # define ECSR_INIT (ECSR_ICD | ECSIPR_MPDIP) #else # define ECSR_INIT (ECSR_BRCRX | ECSR_PSRTO | \ @@ -556,7 +614,7 @@ enum ECSIPR_STATUS_MASK_BIT { ECSIPR_ICDIP = 0x01, }; -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) # define ECSIPR_INIT (ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP) #else # define ECSIPR_INIT (ECSIPR_BRCRXIP | ECSIPR_PSRTOIP | ECSIPR_LCHNGIP | \ @@ -587,7 +645,7 @@ enum RPADIR_BIT { RPADIR_PADR = 0x0003f, }; -#if defined(SH_ETH_TYPE_GETHER) +#if defined(SH_ETH_TYPE_GETHER) || defined(SH_ETH_TYPE_RZ) # define RPADIR_INIT (0x00) #else # define RPADIR_INIT (RPADIR_PADS1) @@ -605,6 +663,8 @@ static inline unsigned long sh_eth_reg_addr(struct sh_eth_dev *eth, const u16 *reg_offset = sh_eth_offset_gigabit; #elif defined(SH_ETH_TYPE_ETHER) const u16 *reg_offset = sh_eth_offset_fast_sh4; +#elif defined(SH_ETH_TYPE_RZ) + const u16 *reg_offset = sh_eth_offset_rz; #else #error #endif diff --git a/drivers/power/battery/bat_trats.c b/drivers/power/battery/bat_trats.c index 41b179f..bfde692 100644 --- a/drivers/power/battery/bat_trats.c +++ b/drivers/power/battery/bat_trats.c @@ -19,7 +19,7 @@ static int power_battery_charge(struct pmic *bat) struct battery *battery = p_bat->bat; int k; - if (bat->chrg->chrg_state(p_bat->chrg, CHARGER_ENABLE, 450)) + if (bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_ENABLE, 450)) return -1; for (k = 0; bat->chrg->chrg_bat_present(p_bat->chrg) && @@ -42,7 +42,7 @@ static int power_battery_charge(struct pmic *bat) } } exit: - bat->chrg->chrg_state(p_bat->chrg, CHARGER_DISABLE, 0); + bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_DISABLE, 0); return 0; } diff --git a/drivers/power/battery/bat_trats2.c b/drivers/power/battery/bat_trats2.c index 94015aa..57221ad 100644 --- a/drivers/power/battery/bat_trats2.c +++ b/drivers/power/battery/bat_trats2.c @@ -17,7 +17,7 @@ static int power_battery_charge(struct pmic *bat) { struct power_battery *p_bat = bat->pbat; - if (bat->chrg->chrg_state(p_bat->chrg, CHARGER_ENABLE, 450)) + if (bat->chrg->chrg_state(p_bat->chrg, PMIC_CHARGER_ENABLE, 450)) return -1; return 0; diff --git a/drivers/power/mfd/pmic_max77693.c b/drivers/power/mfd/pmic_max77693.c index 1a4416b..6b28e28 100644 --- a/drivers/power/mfd/pmic_max77693.c +++ b/drivers/power/mfd/pmic_max77693.c @@ -22,7 +22,7 @@ static int max77693_charger_state(struct pmic *p, int state, int current) val = MAX77693_CHG_UNLOCK; pmic_reg_write(p, MAX77693_CHG_CNFG_06, val); - if (state == CHARGER_DISABLE) { + if (state == PMIC_CHARGER_DISABLE) { puts("Disable the charger.\n"); pmic_reg_read(p, MAX77693_CHG_CNFG_00, &val); val &= ~0x01; diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 920bbdc..a472f61 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -11,5 +11,7 @@ obj-$(CONFIG_POWER_MAX8997) += pmic_max8997.o obj-$(CONFIG_POWER_MUIC_MAX8997) += muic_max8997.o obj-$(CONFIG_POWER_MAX77686) += pmic_max77686.o obj-$(CONFIG_POWER_PFUZE100) += pmic_pfuze100.o +obj-$(CONFIG_POWER_TPS65090) += pmic_tps65090.o obj-$(CONFIG_POWER_TPS65217) += pmic_tps65217.o +obj-$(CONFIG_POWER_TPS65218) += pmic_tps65218.o obj-$(CONFIG_POWER_TPS65910) += pmic_tps65910.o diff --git a/drivers/power/pmic/pmic_max8997.c b/drivers/power/pmic/pmic_max8997.c index ba01692..a36a9a0 100644 --- a/drivers/power/pmic/pmic_max8997.c +++ b/drivers/power/pmic/pmic_max8997.c @@ -35,7 +35,7 @@ static int pmic_charger_state(struct pmic *p, int state, int current) if (pmic_probe(p)) return -1; - if (state == CHARGER_DISABLE) { + if (state == PMIC_CHARGER_DISABLE) { puts("Disable the charger.\n"); pmic_reg_read(p, MAX8997_REG_MBCCTRL2, &val); val &= ~(MBCHOSTEN | VCHGR_FC); diff --git a/drivers/power/pmic/pmic_tps65090.c b/drivers/power/pmic/pmic_tps65090.c new file mode 100644 index 0000000..c5b3966 --- /dev/null +++ b/drivers/power/pmic/pmic_tps65090.c @@ -0,0 +1,310 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <fdtdec.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/tps65090_pmic.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define TPS65090_NAME "TPS65090_PMIC" + +/* TPS65090 register addresses */ +enum { + REG_IRQ1 = 0, + REG_CG_CTRL0 = 4, + REG_CG_STATUS1 = 0xa, + REG_FET1_CTRL = 0x0f, + REG_FET2_CTRL, + REG_FET3_CTRL, + REG_FET4_CTRL, + REG_FET5_CTRL, + REG_FET6_CTRL, + REG_FET7_CTRL, + TPS65090_NUM_REGS, +}; + +enum { + IRQ1_VBATG = 1 << 3, + CG_CTRL0_ENC_MASK = 0x01, + + MAX_FET_NUM = 7, + MAX_CTRL_READ_TRIES = 5, + + /* TPS65090 FET_CTRL register values */ + FET_CTRL_TOFET = 1 << 7, /* Timeout, startup, overload */ + FET_CTRL_PGFET = 1 << 4, /* Power good for FET status */ + FET_CTRL_WAIT = 3 << 2, /* Overcurrent timeout max */ + FET_CTRL_ADENFET = 1 << 1, /* Enable output auto discharge */ + FET_CTRL_ENFET = 1 << 0, /* Enable FET */ +}; + +/** + * Checks for a valid FET number + * + * @param fet_id FET number to check + * @return 0 if ok, -EINVAL if FET value is out of range + */ +static int tps65090_check_fet(unsigned int fet_id) +{ + if (fet_id == 0 || fet_id > MAX_FET_NUM) { + debug("parameter fet_id is out of range, %u not in 1 ~ %u\n", + fet_id, MAX_FET_NUM); + return -EINVAL; + } + + return 0; +} + +/** + * Set the power state for a FET + * + * @param pmic pmic structure for the tps65090 + * @param fet_id Fet number to set (1..MAX_FET_NUM) + * @param set 1 to power on FET, 0 to power off + * @return -EIO if we got a comms error, -EAGAIN if the FET failed to + * change state. If all is ok, returns 0. + */ +static int tps65090_fet_set(struct pmic *pmic, int fet_id, bool set) +{ + int retry; + u32 reg, value; + + value = FET_CTRL_ADENFET | FET_CTRL_WAIT; + if (set) + value |= FET_CTRL_ENFET; + + if (pmic_reg_write(pmic, REG_FET1_CTRL + fet_id - 1, value)) + return -EIO; + + /* Try reading until we get a result */ + for (retry = 0; retry < MAX_CTRL_READ_TRIES; retry++) { + if (pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®)) + return -EIO; + + /* Check that the fet went into the expected state */ + if (!!(reg & FET_CTRL_PGFET) == set) + return 0; + + /* If we got a timeout, there is no point in waiting longer */ + if (reg & FET_CTRL_TOFET) + break; + + mdelay(1); + } + + debug("FET %d: Power good should have set to %d but reg=%#02x\n", + fet_id, set, reg); + return -EAGAIN; +} + +int tps65090_fet_enable(unsigned int fet_id) +{ + struct pmic *pmic; + ulong start; + int loops; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + start = get_timer(0); + for (loops = 0;; loops++) { + ret = tps65090_fet_set(pmic, fet_id, true); + if (!ret) + break; + + if (get_timer(start) > 100) + break; + + /* Turn it off and try again until we time out */ + tps65090_fet_set(pmic, fet_id, false); + } + + if (ret) + debug("%s: FET%d failed to power on: time=%lums, loops=%d\n", + __func__, fet_id, get_timer(start), loops); + else if (loops) + debug("%s: FET%d powered on after %lums, loops=%d\n", + __func__, fet_id, get_timer(start), loops); + + /* + * Unfortunately, there are some conditions where the power + * good bit will be 0, but the fet still comes up. One such + * case occurs with the lcd backlight. We'll just return 0 here + * and assume that the fet will eventually come up. + */ + if (ret == -EAGAIN) + ret = 0; + + return ret; +} + +int tps65090_fet_disable(unsigned int fet_id) +{ + struct pmic *pmic; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + ret = tps65090_fet_set(pmic, fet_id, false); + + return ret; +} + +int tps65090_fet_is_enabled(unsigned int fet_id) +{ + struct pmic *pmic; + u32 reg; + int ret; + + ret = tps65090_check_fet(fet_id); + if (ret) + return ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -ENODEV; + ret = pmic_reg_read(pmic, REG_FET1_CTRL + fet_id - 1, ®); + if (ret) { + debug("fail to read FET%u_CTRL register over I2C", fet_id); + return -EIO; + } + + return reg & FET_CTRL_ENFET; +} + +int tps65090_get_charging(void) +{ + struct pmic *pmic; + u32 val; + int ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val); + if (ret) + return ret; + + return !!(val & CG_CTRL0_ENC_MASK); +} + +static int tps65090_charger_state(struct pmic *pmic, int state, + int current) +{ + u32 val; + int ret; + + ret = pmic_reg_read(pmic, REG_CG_CTRL0, &val); + if (!ret) { + if (state == PMIC_CHARGER_ENABLE) + val |= CG_CTRL0_ENC_MASK; + else + val &= ~CG_CTRL0_ENC_MASK; + ret = pmic_reg_write(pmic, REG_CG_CTRL0, val); + } + if (ret) { + debug("%s: Failed to read/write register\n", __func__); + return ret; + } + + return 0; +} + +int tps65090_get_status(void) +{ + struct pmic *pmic; + u32 val; + int ret; + + pmic = pmic_get(TPS65090_NAME); + if (!pmic) + return -EACCES; + + ret = pmic_reg_read(pmic, REG_CG_STATUS1, &val); + if (ret) + return ret; + + return val; +} + +static int tps65090_charger_bat_present(struct pmic *pmic) +{ + u32 val; + int ret; + + ret = pmic_reg_read(pmic, REG_IRQ1, &val); + if (ret) + return ret; + + return !!(val & IRQ1_VBATG); +} + +static struct power_chrg power_chrg_pmic_ops = { + .chrg_bat_present = tps65090_charger_bat_present, + .chrg_state = tps65090_charger_state, +}; + +int tps65090_init(void) +{ + struct pmic *p; + int bus; + int addr; + const void *blob = gd->fdt_blob; + int node, parent; + + node = fdtdec_next_compatible(blob, 0, COMPAT_TI_TPS65090); + if (node < 0) { + debug("PMIC: No node for PMIC Chip in device tree\n"); + debug("node = %d\n", node); + return -ENODEV; + } + + parent = fdt_parent_offset(blob, node); + if (parent < 0) { + debug("%s: Cannot find node parent\n", __func__); + return -EINVAL; + } + + bus = i2c_get_bus_num_fdt(parent); + if (p->bus < 0) { + debug("%s: Cannot find I2C bus\n", __func__); + return -ENOENT; + } + addr = fdtdec_get_int(blob, node, "reg", TPS65090_I2C_ADDR); + p = pmic_alloc(); + if (!p) { + printf("%s: POWER allocation error!\n", __func__); + return -ENOMEM; + } + + p->name = TPS65090_NAME; + p->bus = bus; + p->interface = PMIC_I2C; + p->number_of_regs = TPS65090_NUM_REGS; + p->hw.i2c.addr = addr; + p->hw.i2c.tx_num = 1; + p->chrg = &power_chrg_pmic_ops; + + puts("TPS65090 PMIC init\n"); + + return 0; +} diff --git a/drivers/power/pmic/pmic_tps65218.c b/drivers/power/pmic/pmic_tps65218.c new file mode 100644 index 0000000..0952456 --- /dev/null +++ b/drivers/power/pmic/pmic_tps65218.c @@ -0,0 +1,97 @@ +/* + * (C) Copyright 2011-2013 + * Texas Instruments, <www.ti.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <i2c.h> +#include <power/tps65218.h> + +/** + * tps65218_reg_write() - Generic function that can write a TPS65218 PMIC + * register or bit field regardless of protection + * level. + * + * @prot_level: Register password protection. Use + * TPS65218_PROT_LEVEL_NONE, + * TPS65218_PROT_LEVEL_1 or TPS65218_PROT_LEVEL_2 + * @dest_reg: Register address to write. + * @dest_val: Value to write. + * @mask: Bit mask (8 bits) to be applied. Function will only + * change bits that are set in the bit mask. + * + * @return: 0 for success, not 0 on failure, as per the i2c API + */ +int tps65218_reg_write(uchar prot_level, uchar dest_reg, uchar dest_val, + uchar mask) +{ + uchar read_val; + uchar xor_reg; + int ret; + + /* + * If we are affecting only a bit field, read dest_reg and apply the + * mask + */ + if (mask != TPS65218_MASK_ALL_BITS) { + ret = i2c_read(TPS65218_CHIP_PM, dest_reg, 1, &read_val, 1); + if (ret) + return ret; + read_val &= (~mask); + read_val |= (dest_val & mask); + dest_val = read_val; + } + + if (prot_level > 0) { + xor_reg = dest_reg ^ TPS65218_PASSWORD_UNLOCK; + ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1, + &xor_reg, 1); + if (ret) + return ret; + } + + ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1); + if (ret) + return ret; + + if (prot_level == TPS65218_PROT_LEVEL_2) { + ret = i2c_write(TPS65218_CHIP_PM, TPS65218_PASSWORD, 1, + &xor_reg, 1); + if (ret) + return ret; + + ret = i2c_write(TPS65218_CHIP_PM, dest_reg, 1, &dest_val, 1); + if (ret) + return ret; + } + + return 0; +} + +/** + * tps65218_voltage_update() - Function to change a voltage level, as this + * is a multi-step process. + * @dc_cntrl_reg: DC voltage control register to change. + * @volt_sel: New value for the voltage register + * @return: 0 for success, not 0 on failure. + */ +int tps65218_voltage_update(uchar dc_cntrl_reg, uchar volt_sel) +{ + if ((dc_cntrl_reg != TPS65218_DCDC1) && + (dc_cntrl_reg != TPS65218_DCDC2)) + return 1; + + /* set voltage level */ + if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, dc_cntrl_reg, volt_sel, + TPS65218_MASK_ALL_BITS)) + return 1; + + /* set GO bit to initiate voltage transition */ + if (tps65218_reg_write(TPS65218_PROT_LEVEL_2, TPS65218_SLEW, + TPS65218_DCDC_GO, TPS65218_DCDC_GO)) + return 1; + + return 0; +} diff --git a/drivers/power/power_fsl.c b/drivers/power/power_fsl.c index ac0b541..a64161b 100644 --- a/drivers/power/power_fsl.c +++ b/drivers/power/power_fsl.c @@ -11,9 +11,9 @@ #include <fsl_pmic.h> #include <errno.h> -#if defined(CONFIG_PMIC_FSL_MC13892) +#if defined(CONFIG_POWER_FSL_MC13892) #define FSL_PMIC_I2C_LENGTH 3 -#elif defined(CONFIG_PMIC_FSL_MC34704) +#elif defined(CONFIG_POWER_FSL_MC34704) #define FSL_PMIC_I2C_LENGTH 1 #endif @@ -51,7 +51,7 @@ int pmic_init(unsigned char bus) p->hw.i2c.addr = CONFIG_SYS_FSL_PMIC_I2C_ADDR; p->hw.i2c.tx_num = FSL_PMIC_I2C_LENGTH; #else -#error "You must select CONFIG_POWER_SPI or CONFIG_PMIC_I2C" +#error "You must select CONFIG_POWER_SPI or CONFIG_POWER_I2C" #endif return 0; diff --git a/drivers/power/power_i2c.c b/drivers/power/power_i2c.c index ac76870..594cd11 100644 --- a/drivers/power/power_i2c.c +++ b/drivers/power/power_i2c.c @@ -23,6 +23,8 @@ int pmic_reg_write(struct pmic *p, u32 reg, u32 val) if (check_reg(p, reg)) return -1; + I2C_SET_BUS(p->bus); + switch (pmic_i2c_tx_num) { case 3: if (p->sensor_byte_order == PMIC_SENSOR_BYTE_ORDER_BIG) { @@ -66,6 +68,8 @@ int pmic_reg_read(struct pmic *p, u32 reg, u32 *val) if (check_reg(p, reg)) return -1; + I2C_SET_BUS(p->bus); + if (i2c_read(pmic_i2c_addr, reg, 1, buf, pmic_i2c_tx_num)) return -1; diff --git a/drivers/spi/fsl_espi.c b/drivers/spi/fsl_espi.c index 7c84582..ae0fe58 100644 --- a/drivers/spi/fsl_espi.c +++ b/drivers/spi/fsl_espi.c @@ -15,8 +15,10 @@ struct fsl_spi_slave { struct spi_slave slave; + ccsr_espi_t *espi; unsigned int div16; unsigned int pm; + int tx_timeout; unsigned int mode; size_t cmd_len; u8 cmd_buf[16]; @@ -25,11 +27,17 @@ struct fsl_spi_slave { }; #define to_fsl_spi_slave(s) container_of(s, struct fsl_spi_slave, slave) +#define US_PER_SECOND 1000000UL #define ESPI_MAX_CS_NUM 4 +#define ESPI_FIFO_WIDTH_BIT 32 #define ESPI_EV_RNE (1 << 9) #define ESPI_EV_TNF (1 << 8) +#define ESPI_EV_DON (1 << 14) +#define ESPI_EV_TXE (1 << 15) +#define ESPI_EV_RFCNT_SHIFT 24 +#define ESPI_EV_RFCNT_MASK (0x3f << ESPI_EV_RFCNT_SHIFT) #define ESPI_MODE_EN (1 << 31) /* Enable interface */ #define ESPI_MODE_TXTHR(x) ((x) << 8) /* Tx FIFO threshold */ @@ -61,6 +69,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, struct fsl_spi_slave *fsl; sys_info_t sysinfo; unsigned long spibrg = 0; + unsigned long spi_freq = 0; unsigned char pm = 0; if (!spi_cs_is_valid(bus, cs)) @@ -70,6 +79,7 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, if (!fsl) return NULL; + fsl->espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); fsl->mode = mode; fsl->max_transfer_length = ESPI_MAX_DATA_TRANSFER_LEN; @@ -91,6 +101,15 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, pm--; fsl->pm = pm; + if (fsl->div16) + spi_freq = spibrg / ((pm + 1) * 2 * 16); + else + spi_freq = spibrg / ((pm + 1) * 2); + + /* set tx_timeout to 10 times of one espi FIFO entry go out */ + fsl->tx_timeout = DIV_ROUND_UP((US_PER_SECOND * ESPI_FIFO_WIDTH_BIT + * 10), spi_freq); + return &fsl->slave; } @@ -108,7 +127,7 @@ void spi_init(void) int spi_claim_bus(struct spi_slave *slave) { struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave); - ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); + ccsr_espi_t *espi = fsl->espi; unsigned char pm = fsl->pm; unsigned int cs = slave->cs; unsigned int mode = fsl->mode; @@ -161,24 +180,86 @@ void spi_release_bus(struct spi_slave *slave) } +static void fsl_espi_tx(struct fsl_spi_slave *fsl, const void *dout) +{ + ccsr_espi_t *espi = fsl->espi; + unsigned int tmpdout, event; + int tmp_tx_timeout; + + if (dout) + tmpdout = *(u32 *)dout; + else + tmpdout = 0; + + out_be32(&espi->tx, tmpdout); + out_be32(&espi->event, ESPI_EV_TNF); + debug("***spi_xfer:...%08x written\n", tmpdout); + + tmp_tx_timeout = fsl->tx_timeout; + /* Wait for eSPI transmit to go out */ + while (tmp_tx_timeout--) { + event = in_be32(&espi->event); + if (event & ESPI_EV_DON || event & ESPI_EV_TXE) { + out_be32(&espi->event, ESPI_EV_TXE); + break; + } + udelay(1); + } + + if (tmp_tx_timeout < 0) + debug("***spi_xfer:...Tx timeout! event = %08x\n", event); +} + +static int fsl_espi_rx(struct fsl_spi_slave *fsl, void *din, unsigned int bytes) +{ + ccsr_espi_t *espi = fsl->espi; + unsigned int tmpdin, rx_times; + unsigned char *buf, *p_cursor; + + if (bytes <= 0) + return 0; + + rx_times = DIV_ROUND_UP(bytes, 4); + buf = (unsigned char *)malloc(4 * rx_times); + if (!buf) { + debug("SF: Failed to malloc memory.\n"); + return -1; + } + p_cursor = buf; + while (rx_times--) { + tmpdin = in_be32(&espi->rx); + debug("***spi_xfer:...%08x readed\n", tmpdin); + *(u32 *)p_cursor = tmpdin; + p_cursor += 4; + } + + if (din) + memcpy(din, buf, bytes); + + free(buf); + out_be32(&espi->event, ESPI_EV_RNE); + + return bytes; +} + int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, void *data_in, unsigned long flags) { struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave); - ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); - unsigned int tmpdout, tmpdin, event; + ccsr_espi_t *espi = fsl->espi; + unsigned int event, rx_bytes; const void *dout = NULL; void *din = NULL; int len = 0; int num_blks, num_chunks, max_tran_len, tran_len; int num_bytes; - unsigned char *ch; unsigned char *buffer = NULL; size_t buf_len; u8 *cmd_buf = fsl->cmd_buf; size_t cmd_len = fsl->cmd_len; size_t data_len = bitlen / 8; size_t rx_offset = 0; + int rf_cnt; max_tran_len = fsl->max_transfer_length; switch (flags) { @@ -217,9 +298,8 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, break; } - debug("spi_xfer: slave %u:%u dout %08X(%p) din %08X(%p) len %u\n", - slave->bus, slave->cs, *(uint *) dout, - dout, *(uint *) din, din, len); + debug("spi_xfer: data_out %08X(%p) data_in %08X(%p) len %u\n", + *(uint *)data_out, data_out, *(uint *)data_in, data_in, len); num_chunks = DIV_ROUND_UP(data_len, max_tran_len); while (num_chunks--) { @@ -235,41 +315,34 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *data_out, /* Clear all eSPI events */ out_be32(&espi->event , 0xffffffff); /* handle data in 32-bit chunks */ - while (num_blks--) { - + while (num_blks) { event = in_be32(&espi->event); if (event & ESPI_EV_TNF) { - tmpdout = *(u32 *)dout; - + fsl_espi_tx(fsl, dout); /* Set up the next iteration */ if (len > 4) { len -= 4; dout += 4; } - - out_be32(&espi->tx, tmpdout); - out_be32(&espi->event, ESPI_EV_TNF); - debug("***spi_xfer:...%08x written\n", tmpdout); } - /* Wait for eSPI transmit to get out */ - udelay(80); - event = in_be32(&espi->event); if (event & ESPI_EV_RNE) { - tmpdin = in_be32(&espi->rx); - if (num_blks == 0 && num_bytes != 0) { - ch = (unsigned char *)&tmpdin; - while (num_bytes--) - *(unsigned char *)din++ = *ch++; - } else { - *(u32 *) din = tmpdin; - din += 4; + rf_cnt = ((event & ESPI_EV_RFCNT_MASK) + >> ESPI_EV_RFCNT_SHIFT); + if (rf_cnt >= 4) + rx_bytes = 4; + else if (num_blks == 1 && rf_cnt == num_bytes) + rx_bytes = num_bytes; + else + continue; + if (fsl_espi_rx(fsl, din, rx_bytes) + == rx_bytes) { + num_blks--; + if (din) + din = (unsigned char *)din + + rx_bytes; } - - out_be32(&espi->event, in_be32(&espi->event) - | ESPI_EV_RNE); - debug("***spi_xfer:...%08x readed\n", tmpdin); } } if (data_in) { @@ -295,7 +368,7 @@ int spi_cs_is_valid(unsigned int bus, unsigned int cs) void spi_cs_activate(struct spi_slave *slave) { struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave); - ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); + ccsr_espi_t *espi = fsl->espi; unsigned int com = 0; size_t data_len = fsl->data_len; @@ -307,7 +380,8 @@ void spi_cs_activate(struct spi_slave *slave) void spi_cs_deactivate(struct spi_slave *slave) { - ccsr_espi_t *espi = (void *)(CONFIG_SYS_MPC85xx_ESPI_ADDR); + struct fsl_spi_slave *fsl = to_fsl_spi_slave(slave); + ccsr_espi_t *espi = fsl->espi; /* clear the RXCNT and TXCNT */ out_be32(&espi->mode, in_be32(&espi->mode) & (~ESPI_MODE_EN)); diff --git a/drivers/spi/ti_qspi.c b/drivers/spi/ti_qspi.c index c5d2245..fd7fea8 100644 --- a/drivers/spi/ti_qspi.c +++ b/drivers/spi/ti_qspi.c @@ -106,6 +106,7 @@ static void ti_spi_setup_spi_register(struct ti_qspi_slave *qslave) slave->memory_map = (void *)MMAP_START_ADDR_DRA; #else slave->memory_map = (void *)MMAP_START_ADDR_AM43x; + slave->op_mode_rx = 8; #endif memval |= QSPI_CMD_READ | QSPI_SETUP0_NUM_A_BYTES | |