diff options
Diffstat (limited to 'drivers')
51 files changed, 1937 insertions, 952 deletions
diff --git a/drivers/adc/stm32-adc-core.c b/drivers/adc/stm32-adc-core.c index a9aa143bfe..04b6a8a2f5 100644 --- a/drivers/adc/stm32-adc-core.c +++ b/drivers/adc/stm32-adc-core.c @@ -60,7 +60,8 @@ static int stm32h7_adc_clk_sel(struct udevice *dev, { u32 ckmode, presc; unsigned long rate; - int i, div; + unsigned int i; + int div; /* stm32h7 bus clock is common for all ADC instances (mandatory) */ if (!clk_valid(&common->bclk)) { diff --git a/drivers/adc/stm32-adc.c b/drivers/adc/stm32-adc.c index e108062f2f..029338e4af 100644 --- a/drivers/adc/stm32-adc.c +++ b/drivers/adc/stm32-adc.c @@ -163,15 +163,16 @@ static int stm32_adc_chan_of_init(struct udevice *dev) struct adc_uclass_platdata *uc_pdata = dev_get_uclass_platdata(dev); struct stm32_adc *adc = dev_get_priv(dev); u32 chans[STM32_ADC_CH_MAX]; - int i, num_channels, ret; + unsigned int i, num_channels; + int ret; /* Retrieve single ended channels listed in device tree */ - num_channels = dev_read_size(dev, "st,adc-channels"); - if (num_channels < 0) { - dev_err(dev, "can't get st,adc-channels: %d\n", num_channels); - return num_channels; + ret = dev_read_size(dev, "st,adc-channels"); + if (ret < 0) { + dev_err(dev, "can't get st,adc-channels: %d\n", ret); + return ret; } - num_channels /= sizeof(u32); + num_channels = ret / sizeof(u32); if (num_channels > adc->cfg->max_channels) { dev_err(dev, "too many st,adc-channels: %d\n", num_channels); diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c index f295e4864b..6ffa05b8fd 100644 --- a/drivers/clk/clk_stm32mp1.c +++ b/drivers/clk/clk_stm32mp1.c @@ -805,10 +805,11 @@ static int stm32mp1_clk_get_parent(struct stm32mp1_clk_priv *priv, const struct stm32mp1_clk_sel *sel = priv->data->sel; int i; int s, p; + unsigned int idx; - for (i = 0; i < ARRAY_SIZE(stm32mp1_clks); i++) - if (stm32mp1_clks[i][0] == id) - return stm32mp1_clks[i][1]; + for (idx = 0; idx < ARRAY_SIZE(stm32mp1_clks); idx++) + if (stm32mp1_clks[idx][0] == id) + return stm32mp1_clks[idx][1]; i = stm32mp1_clk_get_id(priv, id); if (i < 0) @@ -1542,8 +1543,7 @@ static void stgen_config(struct stm32mp1_clk_priv *priv) u32 stgenc, cntfid0; ulong rate; - stgenc = (u32)syscon_get_first_range(STM32MP_SYSCON_STGEN); - + stgenc = STM32_STGEN_BASE; cntfid0 = readl(stgenc + STGENC_CNTFID0); p = stm32mp1_clk_get_parent(priv, STGEN_K); rate = stm32mp1_clk_get(priv, p); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4532ed3211..800584f512 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -271,13 +271,13 @@ config PIC32_GPIO help Say yes here to support Microchip PIC32 GPIOs. -config STM32F7_GPIO +config STM32_GPIO bool "ST STM32 GPIO driver" depends on DM_GPIO && (STM32 || ARCH_STM32MP) default y help Device model driver support for STM32 GPIO controller. It should be - usable on many stm32 families like stm32f4 & stm32H7. + usable on many stm32 families like stm32f4/f7/h7 and stm32mp1. Tested on STM32F7. config MVEBU_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 7337153e0e..4a8aa0ff6f 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -47,7 +47,7 @@ obj-$(CONFIG_ADI_GPIO2) += adi_gpio2.o obj-$(CONFIG_TCA642X) += tca642x.o obj-$(CONFIG_SUNXI_GPIO) += sunxi_gpio.o obj-$(CONFIG_LPC32XX_GPIO) += lpc32xx_gpio.o -obj-$(CONFIG_STM32F7_GPIO) += stm32f7_gpio.o +obj-$(CONFIG_STM32_GPIO) += stm32_gpio.o obj-$(CONFIG_GPIO_UNIPHIER) += gpio-uniphier.o obj-$(CONFIG_ZYNQ_GPIO) += zynq_gpio.o obj-$(CONFIG_VYBRID_GPIO) += vybrid_gpio.o diff --git a/drivers/gpio/stm32f7_gpio.c b/drivers/gpio/stm32_gpio.c index 5c9f2fe64d..302a434947 100644 --- a/drivers/gpio/stm32f7_gpio.c +++ b/drivers/gpio/stm32_gpio.c @@ -27,7 +27,7 @@ int stm32_offset_to_index(struct udevice *dev, unsigned int offset) { struct stm32_gpio_priv *priv = dev_get_priv(dev); - int idx = 0; + unsigned int idx = 0; int i; for (i = 0; i < STM32_GPIOS_PER_BANK; i++) { @@ -210,15 +210,9 @@ static int gpio_stm32_probe(struct udevice *dev) return 0; } -static const struct udevice_id stm32_gpio_ids[] = { - { .compatible = "st,stm32-gpio" }, - { } -}; - U_BOOT_DRIVER(gpio_stm32) = { .name = "gpio_stm32", .id = UCLASS_GPIO, - .of_match = stm32_gpio_ids, .probe = gpio_stm32_probe, #ifndef CONFIG_SPL_BUILD .ops = &gpio_stm32_ops, diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c index 50c4fd0de2..2b18735fea 100644 --- a/drivers/i2c/stm32f7_i2c.c +++ b/drivers/i2c/stm32f7_i2c.c @@ -519,13 +519,13 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, /* Compute possible values for PRESC, SCLDEL and SDADEL */ for (p = 0; p < STM32_PRESC_MAX; p++) { for (l = 0; l < STM32_SCLDEL_MAX; l++) { - u32 scldel = (l + 1) * (p + 1) * i2cclk; + int scldel = (l + 1) * (p + 1) * i2cclk; if (scldel < scldel_min) continue; for (a = 0; a < STM32_SDADEL_MAX; a++) { - u32 sdadel = (a * (p + 1) + 1) * i2cclk; + int sdadel = (a * (p + 1) + 1) * i2cclk; if (((sdadel >= sdadel_min) && (sdadel <= sdadel_max)) && @@ -613,10 +613,12 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, if ((tscl >= clk_min) && (tscl <= clk_max) && (tscl_h >= i2c_specs[setup->speed].h_min) && (i2cclk < tscl_h)) { - int clk_error = tscl - i2cbus; + u32 clk_error; - if (clk_error < 0) - clk_error = -clk_error; + if (tscl > i2cbus) + clk_error = tscl - i2cbus; + else + clk_error = i2cbus - tscl; if (clk_error < clk_error_prev) { clk_error_prev = clk_error; diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 2836ee4a7b..11bf5522db 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -24,6 +24,13 @@ config TEGRA_HSP This enables support for the NVIDIA Tegra HSP Hw module, which implements doorbells, mailboxes, semaphores, and shared interrupts. +config STM32_IPCC + bool "Enable STM32 IPCC controller support" + depends on DM_MAILBOX && ARCH_STM32MP + help + This enables support for the STM32MP IPCC Hw module, which + implements doorbells between 2 processors. + config K3_SEC_PROXY bool "Texas Instruments K3 Secure Proxy Driver" depends on DM_MAILBOX && ARCH_K3 diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index cd237698ba..a753cc4e68 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -6,5 +6,6 @@ obj-$(CONFIG_$(SPL_)DM_MAILBOX) += mailbox-uclass.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o +obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o obj-$(CONFIG_TEGRA_HSP) += tegra-hsp.o obj-$(CONFIG_K3_SEC_PROXY) += k3-sec-proxy.o diff --git a/drivers/mailbox/stm32-ipcc.c b/drivers/mailbox/stm32-ipcc.c new file mode 100644 index 0000000000..c3df9678a7 --- /dev/null +++ b/drivers/mailbox/stm32-ipcc.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <mailbox-uclass.h> +#include <asm/io.h> + +/* + * IPCC has one set of registers per CPU + * IPCC_PROC_OFFST allows to define cpu registers set base address + * according to the assigned proc_id. + */ + +#define IPCC_PROC_OFFST 0x010 + +#define IPCC_XSCR 0x008 +#define IPCC_XTOYSR 0x00c + +#define IPCC_HWCFGR 0x3f0 +#define IPCFGR_CHAN_MASK GENMASK(7, 0) + +#define RX_BIT_CHAN(chan) BIT(chan) +#define TX_BIT_SHIFT 16 +#define TX_BIT_CHAN(chan) BIT(TX_BIT_SHIFT + (chan)) + +#define STM32_MAX_PROCS 2 + +struct stm32_ipcc { + void __iomem *reg_base; + void __iomem *reg_proc; + u32 proc_id; + u32 n_chans; +}; + +static int stm32_ipcc_request(struct mbox_chan *chan) +{ + struct stm32_ipcc *ipcc = dev_get_priv(chan->dev); + + debug("%s(chan=%p)\n", __func__, chan); + + if (chan->id >= ipcc->n_chans) { + debug("%s failed to request channel: %ld\n", + __func__, chan->id); + return -EINVAL; + } + + return 0; +} + +static int stm32_ipcc_free(struct mbox_chan *chan) +{ + debug("%s(chan=%p)\n", __func__, chan); + + return 0; +} + +static int stm32_ipcc_send(struct mbox_chan *chan, const void *data) +{ + struct stm32_ipcc *ipcc = dev_get_priv(chan->dev); + + debug("%s(chan=%p, data=%p)\n", __func__, chan, data); + + if (readl(ipcc->reg_proc + IPCC_XTOYSR) & BIT(chan->id)) + return -EBUSY; + + /* set channel n occupied */ + setbits_le32(ipcc->reg_proc + IPCC_XSCR, TX_BIT_CHAN(chan->id)); + + return 0; +} + +static int stm32_ipcc_recv(struct mbox_chan *chan, void *data) +{ + struct stm32_ipcc *ipcc = dev_get_priv(chan->dev); + u32 val; + int proc_offset; + + debug("%s(chan=%p, data=%p)\n", __func__, chan, data); + + /* read 'channel occupied' status from other proc */ + proc_offset = ipcc->proc_id ? -IPCC_PROC_OFFST : IPCC_PROC_OFFST; + val = readl(ipcc->reg_proc + proc_offset + IPCC_XTOYSR); + + if (!(val & BIT(chan->id))) + return -ENODATA; + + setbits_le32(ipcc->reg_proc + IPCC_XSCR, RX_BIT_CHAN(chan->id)); + + return 0; +} + +static int stm32_ipcc_probe(struct udevice *dev) +{ + struct stm32_ipcc *ipcc = dev_get_priv(dev); + fdt_addr_t addr; + const fdt32_t *cell; + struct clk clk; + int len, ret; + + debug("%s(dev=%p)\n", __func__, dev); + + addr = dev_read_addr(dev); + if (addr == FDT_ADDR_T_NONE) + return -EINVAL; + + ipcc->reg_base = (void __iomem *)addr; + + /* proc_id */ + cell = dev_read_prop(dev, "st,proc_id", &len); + if (len < sizeof(fdt32_t)) { + dev_dbg(dev, "Missing st,proc_id\n"); + return -EINVAL; + } + + ipcc->proc_id = fdtdec_get_number(cell, 1); + + if (ipcc->proc_id >= STM32_MAX_PROCS) { + dev_err(dev, "Invalid proc_id (%d)\n", ipcc->proc_id); + return -EINVAL; + } + + ipcc->reg_proc = ipcc->reg_base + ipcc->proc_id * IPCC_PROC_OFFST; + + ret = clk_get_by_index(dev, 0, &clk); + if (ret) + return ret; + + ret = clk_enable(&clk); + if (ret) + goto clk_free; + + /* get channel number */ + ipcc->n_chans = readl(ipcc->reg_base + IPCC_HWCFGR); + ipcc->n_chans &= IPCFGR_CHAN_MASK; + + return 0; + +clk_free: + clk_free(&clk); + + return ret; +} + +static const struct udevice_id stm32_ipcc_ids[] = { + { .compatible = "st,stm32mp1-ipcc" }, + { } +}; + +struct mbox_ops stm32_ipcc_mbox_ops = { + .request = stm32_ipcc_request, + .free = stm32_ipcc_free, + .send = stm32_ipcc_send, + .recv = stm32_ipcc_recv, +}; + +U_BOOT_DRIVER(stm32_ipcc) = { + .name = "stm32_ipcc", + .id = UCLASS_MAILBOX, + .of_match = stm32_ipcc_ids, + .probe = stm32_ipcc_probe, + .priv_auto_alloc_size = sizeof(struct stm32_ipcc), + .ops = &stm32_ipcc_mbox_ops, +}; diff --git a/drivers/misc/stm32mp_fuse.c b/drivers/misc/stm32mp_fuse.c index 8dc246b0db..801d946b77 100644 --- a/drivers/misc/stm32mp_fuse.c +++ b/drivers/misc/stm32mp_fuse.c @@ -5,6 +5,7 @@ #include <common.h> #include <command.h> +#include <fuse.h> #include <misc.h> #include <errno.h> #include <dm/device.h> diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index b5180ea4a0..890ef358a0 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -46,6 +46,24 @@ config SPL_DM_MMC if MMC +config MMC_SPI + bool "Support for SPI-based MMC controller" + depends on DM_MMC && DM_SPI + help + This selects SPI-based MMC controllers. + If you have an MMC controller on a SPI bus, say Y here. + + If unsure, say N. + +config MMC_SPI_CRC_ON + bool "Support CRC for SPI-based MMC controller" + depends on MMC_SPI + default y + help + This enables CRC for SPI-based MMC controllers. + + If unsure, say N. + config ARM_PL180_MMCI bool "ARM AMBA Multimedia Card Interface and compatible support" depends on DM_MMC && OF_CONTROL @@ -117,6 +135,18 @@ config SPL_MMC_UHS_SUPPORT cards. The IO voltage must be switchable from 3.3v to 1.8v. The bus frequency can go up to 208MHz (SDR104) +config MMC_HS400_ES_SUPPORT + bool "enable HS400 Enhanced Strobe support" + help + The HS400 Enhanced Strobe mode is support by some eMMC. The bus + frequency is up to 200MHz. This mode does not tune the IO. + +config SPL_MMC_HS400_ES_SUPPORT + bool "enable HS400 Enhanced Strobe support in SPL" + help + The HS400 Enhanced Strobe mode is support by some eMMC. The bus + frequency is up to 200MHz. This mode does not tune the IO. + config MMC_HS400_SUPPORT bool "enable HS400 support" select MMC_HS200_SUPPORT diff --git a/drivers/mmc/fsl_esdhc_imx.c b/drivers/mmc/fsl_esdhc_imx.c index c0d47ba378..43106dec75 100644 --- a/drivers/mmc/fsl_esdhc_imx.c +++ b/drivers/mmc/fsl_esdhc_imx.c @@ -101,7 +101,6 @@ struct fsl_esdhc_plat { struct esdhc_soc_data { u32 flags; - u32 caps; }; /** @@ -146,7 +145,7 @@ struct fsl_esdhc_priv { u32 tuning_start_tap; u32 strobe_dll_delay_target; u32 signal_voltage; -#if IS_ENABLED(CONFIG_DM_REGULATOR) +#if CONFIG_IS_ENABLED(DM_REGULATOR) struct udevice *vqmmc_dev; struct udevice *vmmc_dev; #endif @@ -514,9 +513,9 @@ static int esdhc_send_cmd_common(struct fsl_esdhc_priv *priv, struct mmc *mmc, /* Workaround for ESDHC errata ENGcm03648 */ if (!data && (cmd->resp_type & MMC_RSP_BUSY)) { - int timeout = 6000; + int timeout = 50000; - /* Poll on DATA0 line for cmd with busy signal for 600 ms */ + /* Poll on DATA0 line for cmd with busy signal for 5000 ms */ while (timeout > 0 && !(esdhc_read32(®s->prsstat) & PRSSTAT_DAT0)) { udelay(100); @@ -704,6 +703,7 @@ static int esdhc_change_pinstate(struct udevice *dev) case UHS_SDR104: case MMC_HS_200: case MMC_HS_400: + case MMC_HS_400_ES: ret = pinctrl_select_state(dev, "state_200mhz"); break; default: @@ -774,6 +774,7 @@ static int esdhc_set_timing(struct mmc *mmc) writel(mixctrl, ®s->mixctrl); break; case MMC_HS_400: + case MMC_HS_400_ES: mixctrl |= MIX_CTRL_DDREN | MIX_CTRL_HS400_EN; writel(mixctrl, ®s->mixctrl); esdhc_set_strobe_dll(mmc); @@ -1426,10 +1427,8 @@ static int fsl_esdhc_probe(struct udevice *dev) priv->esdhc_regs = (struct fsl_esdhc *)addr; priv->dev = dev; priv->mode = -1; - if (data) { + if (data) priv->flags = data->flags; - priv->caps = data->caps; - } val = dev_read_u32_default(dev, "bus-width", -1); if (val == 8) @@ -1490,9 +1489,6 @@ static int fsl_esdhc_probe(struct udevice *dev) } #endif - if (fdt_get_property(fdt, node, "no-1-8-v", NULL)) - priv->caps &= ~(UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_HS400); - /* * TODO: * Because lack of clk driver, if SDHC clk is not enabled, @@ -1515,7 +1511,7 @@ static int fsl_esdhc_probe(struct udevice *dev) init_clk_usdhc(dev->seq); - if (IS_ENABLED(CONFIG_CLK)) { + if (CONFIG_IS_ENABLED(CLK)) { /* Assigned clock already set clock */ ret = clk_get_by_name(dev, "per", &priv->per_clk); if (ret) { @@ -1543,6 +1539,10 @@ static int fsl_esdhc_probe(struct udevice *dev) return ret; } + ret = mmc_of_parse(dev, &plat->cfg); + if (ret) + return ret; + mmc = &plat->mmc; mmc->cfg = &plat->cfg; mmc->dev = dev; @@ -1596,6 +1596,21 @@ static int fsl_esdhc_set_ios(struct udevice *dev) return esdhc_set_ios_common(priv, &plat->mmc); } +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) +static int fsl_esdhc_set_enhanced_strobe(struct udevice *dev) +{ + struct fsl_esdhc_priv *priv = dev_get_priv(dev); + struct fsl_esdhc *regs = priv->esdhc_regs; + u32 m; + + m = readl(®s->mixctrl); + m |= MIX_CTRL_HS400_ES; + writel(m, ®s->mixctrl); + + return 0; +} +#endif + static const struct dm_mmc_ops fsl_esdhc_ops = { .get_cd = fsl_esdhc_get_cd, .send_cmd = fsl_esdhc_send_cmd, @@ -1603,6 +1618,9 @@ static const struct dm_mmc_ops fsl_esdhc_ops = { #ifdef MMC_SUPPORTS_TUNING .execute_tuning = fsl_esdhc_execute_tuning, #endif +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) + .set_enhanced_strobe = fsl_esdhc_set_enhanced_strobe, +#endif }; #endif @@ -1610,8 +1628,12 @@ static struct esdhc_soc_data usdhc_imx7d_data = { .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | ESDHC_FLAG_HS400, - .caps = UHS_CAPS | MMC_MODE_HS200 | MMC_MODE_DDR_52MHz | - MMC_MODE_HS_52MHz | MMC_MODE_HS, +}; + +static struct esdhc_soc_data usdhc_imx8qm_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING | + ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 | + ESDHC_FLAG_HS400 | ESDHC_FLAG_HS400_ES, }; static const struct udevice_id fsl_esdhc_ids[] = { @@ -1622,6 +1644,7 @@ static const struct udevice_id fsl_esdhc_ids[] = { { .compatible = "fsl,imx6q-usdhc", }, { .compatible = "fsl,imx7d-usdhc", .data = (ulong)&usdhc_imx7d_data,}, { .compatible = "fsl,imx7ulp-usdhc", }, + { .compatible = "fsl,imx8qm-usdhc", .data = (ulong)&usdhc_imx8qm_data,}, { .compatible = "fsl,esdhc", }, { /* sentinel */ } }; diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c index a9c8f335c1..551007905c 100644 --- a/drivers/mmc/mmc-uclass.c +++ b/drivers/mmc/mmc-uclass.c @@ -47,20 +47,6 @@ int mmc_set_ios(struct mmc *mmc) return dm_mmc_set_ios(mmc->dev); } -void dm_mmc_send_init_stream(struct udevice *dev) -{ - struct dm_mmc_ops *ops = mmc_get_ops(dev); - - if (ops->send_init_stream) - ops->send_init_stream(dev); -} - -void mmc_send_init_stream(struct mmc *mmc) -{ - dm_mmc_send_init_stream(mmc->dev); -} - -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout) { struct dm_mmc_ops *ops = mmc_get_ops(dev); @@ -74,7 +60,6 @@ int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) { return dm_mmc_wait_dat0(mmc->dev, state, timeout); } -#endif int dm_mmc_get_wp(struct udevice *dev) { @@ -120,6 +105,23 @@ int mmc_execute_tuning(struct mmc *mmc, uint opcode) } #endif +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) +int dm_mmc_set_enhanced_strobe(struct udevice *dev) +{ + struct dm_mmc_ops *ops = mmc_get_ops(dev); + + if (ops->set_enhanced_strobe) + return ops->set_enhanced_strobe(dev); + + return -ENOTSUPP; +} + +int mmc_set_enhanced_strobe(struct mmc *mmc) +{ + return dm_mmc_set_enhanced_strobe(mmc->dev); +} +#endif + int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) { int val; @@ -170,6 +172,22 @@ int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) cfg->host_caps |= MMC_CAP(MMC_HS_400); if (dev_read_bool(dev, "mmc-hs400-1_2v")) cfg->host_caps |= MMC_CAP(MMC_HS_400); + if (dev_read_bool(dev, "mmc-hs400-enhanced-strobe")) + cfg->host_caps |= MMC_CAP(MMC_HS_400_ES); + + if (dev_read_bool(dev, "non-removable")) { + cfg->host_caps |= MMC_CAP_NONREMOVABLE; + } else { + if (dev_read_bool(dev, "cd-inverted")) + cfg->host_caps |= MMC_CAP_CD_ACTIVE_HIGH; + if (dev_read_bool(dev, "broken-cd")) + cfg->host_caps |= MMC_CAP_NEEDS_POLL; + } + + if (dev_read_bool(dev, "no-1-8-v")) { + cfg->host_caps &= ~(UHS_CAPS | MMC_MODE_HS200 | + MMC_MODE_HS400 | MMC_MODE_HS400_ES); + } return 0; } diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 71b52c6cf2..c9aa13b409 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -21,6 +21,8 @@ #include <div64.h> #include "mmc_private.h" +#define DEFAULT_CMD6_TIMEOUT_MS 500 + static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage); static int mmc_power_cycle(struct mmc *mmc); #if !CONFIG_IS_ENABLED(MMC_TINY) @@ -29,12 +31,10 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps); #if !CONFIG_IS_ENABLED(DM_MMC) -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) { return -ENOSYS; } -#endif __weak int board_mmc_getwp(struct mmc *mmc) { @@ -148,6 +148,7 @@ const char *mmc_mode_name(enum bus_mode mode) [MMC_DDR_52] = "MMC DDR52 (52MHz)", [MMC_HS_200] = "HS200 (200MHz)", [MMC_HS_400] = "HS400 (200MHz)", + [MMC_HS_400_ES] = "HS400ES (200MHz)", }; if (mode >= MMC_MODES_END) @@ -173,6 +174,7 @@ static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) [UHS_SDR104] = 208000000, [MMC_HS_200] = 200000000, [MMC_HS_400] = 200000000, + [MMC_HS_400_ES] = 200000000, }; if (mode == MMC_LEGACY) @@ -206,7 +208,7 @@ int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) } #endif -int mmc_send_status(struct mmc *mmc, int timeout) +int mmc_send_status(struct mmc *mmc, unsigned int *status) { struct mmc_cmd cmd; int err, retries = 5; @@ -216,23 +218,43 @@ int mmc_send_status(struct mmc *mmc, int timeout) if (!mmc_host_is_spi(mmc)) cmd.cmdarg = mmc->rca << 16; - while (1) { + while (retries--) { err = mmc_send_cmd(mmc, &cmd, NULL); if (!err) { - if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && - (cmd.response[0] & MMC_STATUS_CURR_STATE) != - MMC_STATE_PRG) - break; + mmc_trace_state(mmc, &cmd); + *status = cmd.response[0]; + return 0; + } + } + mmc_trace_state(mmc, &cmd); + return -ECOMM; +} + +int mmc_poll_for_busy(struct mmc *mmc, int timeout) +{ + unsigned int status; + int err; + + err = mmc_wait_dat0(mmc, 1, timeout); + if (err != -ENOSYS) + return err; - if (cmd.response[0] & MMC_STATUS_MASK) { + while (1) { + err = mmc_send_status(mmc, &status); + if (err) + return err; + + if ((status & MMC_STATUS_RDY_FOR_DATA) && + (status & MMC_STATUS_CURR_STATE) != + MMC_STATE_PRG) + break; + + if (status & MMC_STATUS_MASK) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) - pr_err("Status Error: 0x%08x\n", - cmd.response[0]); + pr_err("Status Error: 0x%08x\n", status); #endif - return -ECOMM; - } - } else if (--retries < 0) - return err; + return -ECOMM; + } if (timeout-- <= 0) break; @@ -240,7 +262,6 @@ int mmc_send_status(struct mmc *mmc, int timeout) udelay(1000); } - mmc_trace_state(mmc, &cmd); if (timeout <= 0) { #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) pr_err("Timeout waiting card ready\n"); @@ -727,36 +748,67 @@ static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, bool send_status) { + unsigned int status, start; struct mmc_cmd cmd; - int timeout = 1000; + int timeout = DEFAULT_CMD6_TIMEOUT_MS; + bool is_part_switch = (set == EXT_CSD_CMD_SET_NORMAL) && + (index == EXT_CSD_PART_CONF); int retries = 3; int ret; + if (mmc->gen_cmd6_time) + timeout = mmc->gen_cmd6_time * 10; + + if (is_part_switch && mmc->part_switch_time) + timeout = mmc->part_switch_time * 10; + cmd.cmdidx = MMC_CMD_SWITCH; cmd.resp_type = MMC_RSP_R1b; cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | (index << 16) | (value << 8); - while (retries > 0) { + do { ret = mmc_send_cmd(mmc, &cmd, NULL); + } while (ret && retries-- > 0); - if (ret) { - retries--; - continue; - } + if (ret) + return ret; - if (!send_status) { - mdelay(50); - return 0; - } + start = get_timer(0); - /* Waiting for the ready status */ - return mmc_send_status(mmc, timeout); - } + /* poll dat0 for rdy/buys status */ + ret = mmc_wait_dat0(mmc, 1, timeout); + if (ret && ret != -ENOSYS) + return ret; - return ret; + /* + * In cases when not allowed to poll by using CMD13 or because we aren't + * capable of polling by using mmc_wait_dat0, then rely on waiting the + * stated timeout to be sufficient. + */ + if (ret == -ENOSYS && !send_status) + mdelay(timeout); + + /* Finally wait until the card is ready or indicates a failure + * to switch. It doesn't hurt to use CMD13 here even if send_status + * is false, because by now (after 'timeout' ms) the bus should be + * reliable. + */ + do { + ret = mmc_send_status(mmc, &status); + + if (!ret && (status & MMC_STATUS_SWITCH_ERROR)) { + pr_debug("switch failed %d/%d/0x%x !\n", set, index, + value); + return -EIO; + } + if (!ret && (status & MMC_STATUS_RDY_FOR_DATA)) + return 0; + udelay(100); + } while (get_timer(start) < timeout); + return -ETIMEDOUT; } int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) @@ -789,6 +841,11 @@ static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode, speed_bits = EXT_CSD_TIMING_HS400; break; #endif +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) + case MMC_HS_400_ES: + speed_bits = EXT_CSD_TIMING_HS400; + break; +#endif case MMC_LEGACY: speed_bits = EXT_CSD_TIMING_LEGACY; break; @@ -859,7 +916,8 @@ static int mmc_get_capabilities(struct mmc *mmc) mmc->card_caps |= MMC_MODE_HS200; } #endif -#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) +#if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) || \ + CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V | EXT_CSD_CARD_TYPE_HS400_1_8V)) { mmc->card_caps |= MMC_MODE_HS400; @@ -873,6 +931,13 @@ static int mmc_get_capabilities(struct mmc *mmc) if (cardtype & EXT_CSD_CARD_TYPE_26) mmc->card_caps |= MMC_MODE_HS; +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) + if (ext_csd[EXT_CSD_STROBE_SUPPORT] && + (mmc->card_caps & MMC_MODE_HS400)) { + mmc->card_caps |= MMC_MODE_HS400_ES; + } +#endif + return 0; } #endif @@ -905,49 +970,17 @@ static int mmc_set_capacity(struct mmc *mmc, int part_num) return 0; } -#if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) -static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num) -{ - int forbidden = 0; - bool change = false; - - if (part_num & PART_ACCESS_MASK) - forbidden = MMC_CAP(MMC_HS_200) | MMC_CAP(MMC_HS_400); - - if (MMC_CAP(mmc->selected_mode) & forbidden) { - pr_debug("selected mode (%s) is forbidden for part %d\n", - mmc_mode_name(mmc->selected_mode), part_num); - change = true; - } else if (mmc->selected_mode != mmc->best_mode) { - pr_debug("selected mode is not optimal\n"); - change = true; - } - - if (change) - return mmc_select_mode_and_width(mmc, - mmc->card_caps & ~forbidden); - - return 0; -} -#else -static inline int mmc_boot_part_access_chk(struct mmc *mmc, - unsigned int part_num) -{ - return 0; -} -#endif - int mmc_switch_part(struct mmc *mmc, unsigned int part_num) { int ret; + int retry = 3; - ret = mmc_boot_part_access_chk(mmc, part_num); - if (ret) - return ret; - - ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, - (mmc->part_config & ~PART_ACCESS_MASK) - | (part_num & PART_ACCESS_MASK)); + do { + ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_PART_CONF, + (mmc->part_config & ~PART_ACCESS_MASK) + | (part_num & PART_ACCESS_MASK)); + } while (ret && retry--); /* * Set the capacity if the switch succeeded or was intended @@ -1504,10 +1537,6 @@ static int mmc_execute_tuning(struct mmc *mmc, uint opcode) } #endif -static void mmc_send_init_stream(struct mmc *mmc) -{ -} - static int mmc_set_ios(struct mmc *mmc) { int ret = 0; @@ -1672,6 +1701,13 @@ static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) mmc_dump_capabilities("host", mmc->host_caps); #endif + if (mmc_host_is_spi(mmc)) { + mmc_set_bus_width(mmc, 1); + mmc_select_mode(mmc, SD_LEGACY); + mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); + return 0; + } + /* Restrict card's capabilities by what the host can do */ caps = card_caps & mmc->host_caps; @@ -1778,6 +1814,7 @@ static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, u32 card_mask = 0; switch (mode) { + case MMC_HS_400_ES: case MMC_HS_400: case MMC_HS_200: if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_8V | @@ -1820,6 +1857,12 @@ static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, #endif static const struct mode_width_tuning mmc_modes_by_pref[] = { +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) + { + .mode = MMC_HS_400_ES, + .widths = MMC_MODE_8BIT, + }, +#endif #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) { .mode = MMC_HS_400, @@ -1917,6 +1960,47 @@ static int mmc_select_hs400(struct mmc *mmc) } #endif +#if CONFIG_IS_ENABLED(MMC_HS400_ES_SUPPORT) +#if !CONFIG_IS_ENABLED(DM_MMC) +static int mmc_set_enhanced_strobe(struct mmc *mmc) +{ + return -ENOTSUPP; +} +#endif +static int mmc_select_hs400es(struct mmc *mmc) +{ + int err; + + err = mmc_set_card_speed(mmc, MMC_HS, true); + if (err) + return err; + + err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, + EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG | + EXT_CSD_BUS_WIDTH_STROBE); + if (err) { + printf("switch to bus width for hs400 failed\n"); + return err; + } + /* TODO: driver strength */ + err = mmc_set_card_speed(mmc, MMC_HS_400_ES, false); + if (err) + return err; + + mmc_select_mode(mmc, MMC_HS_400_ES); + err = mmc_set_clock(mmc, mmc->tran_speed, false); + if (err) + return err; + + return mmc_set_enhanced_strobe(mmc); +} +#else +static int mmc_select_hs400es(struct mmc *mmc) +{ + return -ENOTSUPP; +} +#endif + #define for_each_supported_width(caps, ddr, ecbv) \ for (ecbv = ext_csd_bus_width;\ ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ @@ -1934,6 +2018,13 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) mmc_dump_capabilities("host", mmc->host_caps); #endif + if (mmc_host_is_spi(mmc)) { + mmc_set_bus_width(mmc, 1); + mmc_select_mode(mmc, MMC_LEGACY); + mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); + return 0; + } + /* Restrict card's capabilities by what the host can do */ card_caps &= mmc->host_caps; @@ -1988,6 +2079,13 @@ static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) printf("Select HS400 failed %d\n", err); goto error; } + } else if (mwt->mode == MMC_HS_400_ES) { + err = mmc_select_hs400es(mmc); + if (err) { + printf("Select HS400ES failed %d\n", + err); + goto error; + } } else { /* configure the bus speed (card) */ err = mmc_set_card_speed(mmc, mwt->mode, false); @@ -2122,6 +2220,9 @@ static int mmc_startup_v4(struct mmc *mmc) mmc->capacity_user = capacity; } + if (mmc->version >= MMC_VERSION_4_5) + mmc->gen_cmd6_time = ext_csd[EXT_CSD_GENERIC_CMD6_TIME]; + /* The partition data may be non-zero but it is only * effective if PARTITION_SETTING_COMPLETED is set in * EXT_CSD, so ignore any data if this bit is not set, @@ -2131,6 +2232,11 @@ static int mmc_startup_v4(struct mmc *mmc) part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & EXT_CSD_PARTITION_SETTING_COMPLETED); + mmc->part_switch_time = ext_csd[EXT_CSD_PART_SWITCH_TIME]; + /* Some eMMC set the value too low so set a minimum */ + if (mmc->part_switch_time < MMC_MIN_PART_SWITCH_TIME && mmc->part_switch_time) + mmc->part_switch_time = MMC_MIN_PART_SWITCH_TIME; + /* store the partition info of emmc */ mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || @@ -2664,7 +2770,6 @@ int mmc_get_op_cond(struct mmc *mmc) retry: mmc_set_initial_state(mmc); - mmc_send_init_stream(mmc); /* Reset the Card */ err = mmc_go_idle(mmc); diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h index f49b6eb573..35170d03ab 100644 --- a/drivers/mmc/mmc_private.h +++ b/drivers/mmc/mmc_private.h @@ -11,10 +11,11 @@ #include <mmc.h> -extern int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data); -extern int mmc_send_status(struct mmc *mmc, int timeout); -extern int mmc_set_blocklen(struct mmc *mmc, int len); +int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data); +int mmc_send_status(struct mmc *mmc, unsigned int *status); +int mmc_poll_for_busy(struct mmc *mmc, int timeout); + +int mmc_set_blocklen(struct mmc *mmc, int len); #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT void mmc_adapter_card_type_ident(void); #endif diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index 4f57990d9c..f3d687ae80 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -2,6 +2,8 @@ * generic mmc spi driver * * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw> + * Copyright 2019 Bhargav Shah <bhargavshah1988@gmail.com> + * * Licensed under the GPL-2 or later. */ #include <common.h> @@ -9,21 +11,23 @@ #include <malloc.h> #include <part.h> #include <mmc.h> -#include <spi.h> +#include <stdlib.h> #include <u-boot/crc.h> #include <linux/crc7.h> #include <asm/byteorder.h> +#include <dm.h> +#include <spi.h> /* MMC/SD in SPI mode reports R1 status always */ -#define R1_SPI_IDLE (1 << 0) -#define R1_SPI_ERASE_RESET (1 << 1) -#define R1_SPI_ILLEGAL_COMMAND (1 << 2) -#define R1_SPI_COM_CRC (1 << 3) -#define R1_SPI_ERASE_SEQ (1 << 4) -#define R1_SPI_ADDRESS (1 << 5) -#define R1_SPI_PARAMETER (1 << 6) +#define R1_SPI_IDLE BIT(0) +#define R1_SPI_ERASE_RESET BIT(1) +#define R1_SPI_ILLEGAL_COMMAND BIT(2) +#define R1_SPI_COM_CRC BIT(3) +#define R1_SPI_ERASE_SEQ BIT(4) +#define R1_SPI_ADDRESS BIT(5) +#define R1_SPI_PARAMETER BIT(6) /* R1 bit 7 is always zero, reuse this bit for error */ -#define R1_SPI_ERROR (1 << 7) +#define R1_SPI_ERROR BIT(7) /* Response tokens used to ack each block written: */ #define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f) @@ -34,28 +38,45 @@ /* Read and write blocks start with these tokens and end with crc; * on error, read tokens act like a subset of R2_SPI_* values. */ -#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */ -#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */ -#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */ +/* single block write multiblock read */ +#define SPI_TOKEN_SINGLE 0xfe +/* multiblock write */ +#define SPI_TOKEN_MULTI_WRITE 0xfc +/* terminate multiblock write */ +#define SPI_TOKEN_STOP_TRAN 0xfd /* MMC SPI commands start with a start bit "0" and a transmit bit "1" */ -#define MMC_SPI_CMD(x) (0x40 | (x & 0x3f)) +#define MMC_SPI_CMD(x) (0x40 | (x)) /* bus capability */ -#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34) -#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */ +#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34) +#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */ +#define MMC_SPI_MAX_CLOCK 25000000 /* SD/MMC legacy speed */ /* timeout value */ -#define CTOUT 8 -#define RTOUT 3000000 /* 1 sec */ -#define WTOUT 3000000 /* 1 sec */ +#define CMD_TIMEOUT 8 +#define READ_TIMEOUT 3000000 /* 1 sec */ +#define WRITE_TIMEOUT 3000000 /* 1 sec */ -static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg) +struct mmc_spi_priv { + struct spi_slave *spi; + struct mmc_config cfg; + struct mmc mmc; +}; + +static int mmc_spi_sendcmd(struct udevice *dev, + ushort cmdidx, u32 cmdarg, u32 resp_type, + u8 *resp, u32 resp_size, + bool resp_match, u8 resp_match_value) { - struct spi_slave *spi = mmc->priv; - u8 cmdo[7]; - u8 r1; - int i; + int i, rpos = 0, ret = 0; + u8 cmdo[7], r; + + debug("%s: cmd%d cmdarg=0x%x resp_type=0x%x " + "resp_size=%d resp_match=%d resp_match_value=0x%x\n", + __func__, cmdidx, cmdarg, resp_type, + resp_size, resp_match, resp_match_value); + cmdo[0] = 0xff; cmdo[1] = MMC_SPI_CMD(cmdidx); cmdo[2] = cmdarg >> 24; @@ -63,37 +84,79 @@ static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg) cmdo[4] = cmdarg >> 8; cmdo[5] = cmdarg; cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01; - spi_xfer(spi, sizeof(cmdo) * 8, cmdo, NULL, 0); - for (i = 0; i < CTOUT; i++) { - spi_xfer(spi, 1 * 8, NULL, &r1, 0); - if (i && (r1 & 0x80) == 0) /* r1 response */ - break; + ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, 0); + if (ret) + return ret; + + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); + if (ret) + return ret; + + if (!resp || !resp_size) + return 0; + + debug("%s: cmd%d", __func__, cmdidx); + + if (resp_match) { + r = ~resp_match_value; + i = CMD_TIMEOUT; + while (i--) { + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); + if (ret) + return ret; + debug(" resp%d=0x%x", rpos, r); + rpos++; + if (r == resp_match_value) + break; + } + if (!i && (r != resp_match_value)) + return -ETIMEDOUT; + } + + for (i = 0; i < resp_size; i++) { + if (i == 0 && resp_match) { + resp[i] = resp_match_value; + continue; + } + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); + if (ret) + return ret; + debug(" resp%d=0x%x", rpos, r); + rpos++; + resp[i] = r; } - debug("%s:cmd%d resp%d %x\n", __func__, cmdidx, i, r1); - return r1; + + debug("\n"); + + return 0; } -static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf, - u32 bcnt, u32 bsize) +static int mmc_spi_readdata(struct udevice *dev, + void *xbuf, u32 bcnt, u32 bsize) { - struct spi_slave *spi = mmc->priv; - u8 *buf = xbuf; - u8 r1; u16 crc; - int i; + u8 *buf = xbuf, r1; + int i, ret = 0; + while (bcnt--) { - for (i = 0; i < RTOUT; i++) { - spi_xfer(spi, 1 * 8, NULL, &r1, 0); - if (r1 != 0xff) /* data token */ + for (i = 0; i < READ_TIMEOUT; i++) { + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); + if (ret) + return ret; + if (r1 == SPI_TOKEN_SINGLE) break; } - debug("%s:tok%d %x\n", __func__, i, r1); + debug("%s: data tok%d 0x%x\n", __func__, i, r1); if (r1 == SPI_TOKEN_SINGLE) { - spi_xfer(spi, bsize * 8, NULL, buf, 0); - spi_xfer(spi, 2 * 8, NULL, &crc, 0); + ret = dm_spi_xfer(dev, bsize * 8, NULL, buf, 0); + if (ret) + return ret; + ret = dm_spi_xfer(dev, 2 * 8, NULL, &crc, 0); + if (ret) + return ret; #ifdef CONFIG_MMC_SPI_CRC_ON - if (be_to_cpu16(crc16_ccitt(0, buf, bsize)) != crc) { - debug("%s: CRC error\n", mmc->cfg->name); + if (be16_to_cpu(crc16_ccitt(0, buf, bsize)) != crc) { + debug("%s: data crc error\n", __func__); r1 = R1_SPI_COM_CRC; break; } @@ -105,48 +168,56 @@ static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf, } buf += bsize; } - return r1; + + if (r1 & R1_SPI_COM_CRC) + ret = -ECOMM; + else if (r1) /* other errors */ + ret = -ETIMEDOUT; + + return ret; } -static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf, - u32 bcnt, u32 bsize, int multi) +static int mmc_spi_writedata(struct udevice *dev, const void *xbuf, + u32 bcnt, u32 bsize, int multi) { - struct spi_slave *spi = mmc->priv; const u8 *buf = xbuf; - u8 r1; + u8 r1, tok[2]; u16 crc; - u8 tok[2]; - int i; + int i, ret = 0; + tok[0] = 0xff; tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE; + while (bcnt--) { #ifdef CONFIG_MMC_SPI_CRC_ON crc = cpu_to_be16(crc16_ccitt(0, (u8 *)buf, bsize)); #endif - spi_xfer(spi, 2 * 8, tok, NULL, 0); - spi_xfer(spi, bsize * 8, buf, NULL, 0); - spi_xfer(spi, 2 * 8, &crc, NULL, 0); - for (i = 0; i < CTOUT; i++) { - spi_xfer(spi, 1 * 8, NULL, &r1, 0); + dm_spi_xfer(dev, 2 * 8, tok, NULL, 0); + dm_spi_xfer(dev, bsize * 8, buf, NULL, 0); + dm_spi_xfer(dev, 2 * 8, &crc, NULL, 0); + for (i = 0; i < CMD_TIMEOUT; i++) { + dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); if ((r1 & 0x10) == 0) /* response token */ break; } - debug("%s:tok%d %x\n", __func__, i, r1); + debug("%s: data tok%d 0x%x\n", __func__, i, r1); if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) { - for (i = 0; i < WTOUT; i++) { /* wait busy */ - spi_xfer(spi, 1 * 8, NULL, &r1, 0); + debug("%s: data accepted\n", __func__); + for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */ + dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); if (i && r1 == 0xff) { r1 = 0; break; } } - if (i == WTOUT) { - debug("%s:wtout %x\n", __func__, r1); + if (i == WRITE_TIMEOUT) { + debug("%s: data write timeout 0x%x\n", + __func__, r1); r1 = R1_SPI_ERROR; break; } } else { - debug("%s: err %x\n", __func__, r1); + debug("%s: data error 0x%x\n", __func__, r1); r1 = R1_SPI_COM_CRC; break; } @@ -154,140 +225,204 @@ static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf, } if (multi && bcnt == -1) { /* stop multi write */ tok[1] = SPI_TOKEN_STOP_TRAN; - spi_xfer(spi, 2 * 8, tok, NULL, 0); - for (i = 0; i < WTOUT; i++) { /* wait busy */ - spi_xfer(spi, 1 * 8, NULL, &r1, 0); + dm_spi_xfer(dev, 2 * 8, tok, NULL, 0); + for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */ + dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); if (i && r1 == 0xff) { r1 = 0; break; } } - if (i == WTOUT) { - debug("%s:wstop %x\n", __func__, r1); + if (i == WRITE_TIMEOUT) { + debug("%s: data write timeout 0x%x\n", __func__, r1); r1 = R1_SPI_ERROR; } } - return r1; -} -static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data) -{ - struct spi_slave *spi = mmc->priv; - u8 r1; - int i; - int ret = 0; - debug("%s:cmd%d %x %x\n", __func__, - cmd->cmdidx, cmd->resp_type, cmd->cmdarg); - spi_claim_bus(spi); - spi_cs_activate(spi); - r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg); - if (r1 == 0xff) { /* no response */ - ret = -ENOMEDIUM; - goto done; - } else if (r1 & R1_SPI_COM_CRC) { + if (r1 & R1_SPI_COM_CRC) ret = -ECOMM; - goto done; - } else if (r1 & ~R1_SPI_IDLE) { /* other errors */ + else if (r1) /* other errors */ ret = -ETIMEDOUT; + + return ret; +} + +static int dm_mmc_spi_set_ios(struct udevice *dev) +{ + return 0; +} + +static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + int i, multi, ret = 0; + u8 *resp = NULL; + u32 resp_size = 0; + bool resp_match = false; + u8 resp8 = 0, resp40[5] = { 0 }, resp_match_value = 0; + + dm_spi_claim_bus(dev); + + for (i = 0; i < 4; i++) + cmd->response[i] = 0; + + switch (cmd->cmdidx) { + case SD_CMD_APP_SEND_OP_COND: + case MMC_CMD_SEND_OP_COND: + resp = &resp8; + resp_size = sizeof(resp8); + cmd->cmdarg = 0x40000000; + break; + case SD_CMD_SEND_IF_COND: + resp = (u8 *)&resp40[0]; + resp_size = sizeof(resp40); + resp_match = true; + resp_match_value = R1_SPI_IDLE; + break; + case MMC_CMD_SPI_READ_OCR: + resp = (u8 *)&resp40[0]; + resp_size = sizeof(resp40); + break; + case MMC_CMD_SEND_STATUS: + case MMC_CMD_SET_BLOCKLEN: + case MMC_CMD_SPI_CRC_ON_OFF: + case MMC_CMD_STOP_TRANSMISSION: + resp = &resp8; + resp_size = sizeof(resp8); + resp_match = true; + resp_match_value = 0x0; + break; + case MMC_CMD_SEND_CSD: + case MMC_CMD_SEND_CID: + case MMC_CMD_READ_SINGLE_BLOCK: + case MMC_CMD_READ_MULTIPLE_BLOCK: + case MMC_CMD_WRITE_SINGLE_BLOCK: + case MMC_CMD_WRITE_MULTIPLE_BLOCK: + break; + default: + resp = &resp8; + resp_size = sizeof(resp8); + resp_match = true; + resp_match_value = R1_SPI_IDLE; + break; + }; + + ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg, cmd->resp_type, + resp, resp_size, resp_match, resp_match_value); + if (ret) goto done; - } else if (cmd->resp_type == MMC_RSP_R2) { - r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16); + + switch (cmd->cmdidx) { + case SD_CMD_APP_SEND_OP_COND: + case MMC_CMD_SEND_OP_COND: + cmd->response[0] = (resp8 & R1_SPI_IDLE) ? 0 : OCR_BUSY; + break; + case SD_CMD_SEND_IF_COND: + case MMC_CMD_SPI_READ_OCR: + cmd->response[0] = resp40[4]; + cmd->response[0] |= (uint)resp40[3] << 8; + cmd->response[0] |= (uint)resp40[2] << 16; + cmd->response[0] |= (uint)resp40[1] << 24; + break; + case MMC_CMD_SEND_STATUS: + cmd->response[0] = (resp8 & 0xff) ? + MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA; + break; + case MMC_CMD_SEND_CID: + case MMC_CMD_SEND_CSD: + ret = mmc_spi_readdata(dev, cmd->response, 1, 16); + if (ret) + return ret; for (i = 0; i < 4; i++) - cmd->response[i] = be32_to_cpu(cmd->response[i]); - debug("r128 %x %x %x %x\n", cmd->response[0], cmd->response[1], - cmd->response[2], cmd->response[3]); - } else if (!data) { - switch (cmd->cmdidx) { - case SD_CMD_APP_SEND_OP_COND: - case MMC_CMD_SEND_OP_COND: - cmd->response[0] = (r1 & R1_SPI_IDLE) ? 0 : OCR_BUSY; - break; - case SD_CMD_SEND_IF_COND: - case MMC_CMD_SPI_READ_OCR: - spi_xfer(spi, 4 * 8, NULL, cmd->response, 0); - cmd->response[0] = be32_to_cpu(cmd->response[0]); - debug("r32 %x\n", cmd->response[0]); - break; - case MMC_CMD_SEND_STATUS: - spi_xfer(spi, 1 * 8, NULL, cmd->response, 0); - cmd->response[0] = (cmd->response[0] & 0xff) ? - MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA; - break; - } - } else { - debug("%s:data %x %x %x\n", __func__, - data->flags, data->blocks, data->blocksize); + cmd->response[i] = + cpu_to_be32(cmd->response[i]); + break; + default: + cmd->response[0] = resp8; + break; + } + + debug("%s: cmd%d resp0=0x%x resp1=0x%x resp2=0x%x resp3=0x%x\n", + __func__, cmd->cmdidx, cmd->response[0], cmd->response[1], + cmd->response[2], cmd->response[3]); + + if (data) { + debug("%s: data flags=0x%x blocks=%d block_size=%d\n", + __func__, data->flags, data->blocks, data->blocksize); + multi = (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK); if (data->flags == MMC_DATA_READ) - r1 = mmc_spi_readdata(mmc, data->dest, - data->blocks, data->blocksize); + ret = mmc_spi_readdata(dev, data->dest, + data->blocks, data->blocksize); else if (data->flags == MMC_DATA_WRITE) - r1 = mmc_spi_writedata(mmc, data->src, - data->blocks, data->blocksize, - (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)); - if (r1 & R1_SPI_COM_CRC) - ret = -ECOMM; - else if (r1) /* other errors */ - ret = -ETIMEDOUT; + ret = mmc_spi_writedata(dev, data->src, + data->blocks, data->blocksize, + multi); } + done: - spi_cs_deactivate(spi); - spi_release_bus(spi); + dm_spi_release_bus(dev); + return ret; } -static int mmc_spi_set_ios(struct mmc *mmc) +static int mmc_spi_probe(struct udevice *dev) { - struct spi_slave *spi = mmc->priv; + struct mmc_spi_priv *priv = dev_get_priv(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + char *name; + + priv->spi = dev_get_parent_priv(dev); + if (!priv->spi->max_hz) + priv->spi->max_hz = MMC_SPI_MAX_CLOCK; + priv->spi->speed = 0; + priv->spi->mode = SPI_MODE_0; + priv->spi->wordlen = 8; + + name = malloc(strlen(dev->parent->name) + strlen(dev->name) + 4); + if (!name) + return -ENOMEM; + sprintf(name, "%s:%s", dev->parent->name, dev->name); + + priv->cfg.name = name; + priv->cfg.host_caps = MMC_MODE_SPI; + priv->cfg.voltages = MMC_SPI_VOLTAGE; + priv->cfg.f_min = MMC_SPI_MIN_CLOCK; + priv->cfg.f_max = priv->spi->max_hz; + priv->cfg.part_type = PART_TYPE_DOS; + priv->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + + priv->mmc.cfg = &priv->cfg; + priv->mmc.priv = priv; + priv->mmc.dev = dev; + + upriv->mmc = &priv->mmc; - debug("%s: clock %u\n", __func__, mmc->clock); - if (mmc->clock) - spi_set_speed(spi, mmc->clock); return 0; } -static int mmc_spi_init_p(struct mmc *mmc) +static int mmc_spi_bind(struct udevice *dev) { - struct spi_slave *spi = mmc->priv; - spi_set_speed(spi, MMC_SPI_MIN_CLOCK); - spi_claim_bus(spi); - /* cs deactivated for 100+ clock */ - spi_xfer(spi, 18 * 8, NULL, NULL, 0); - spi_release_bus(spi); - return 0; + struct mmc_spi_priv *priv = dev_get_priv(dev); + + return mmc_bind(dev, &priv->mmc, &priv->cfg); } -static const struct mmc_ops mmc_spi_ops = { - .send_cmd = mmc_spi_request, - .set_ios = mmc_spi_set_ios, - .init = mmc_spi_init_p, +static const struct dm_mmc_ops mmc_spi_ops = { + .send_cmd = dm_mmc_spi_request, + .set_ios = dm_mmc_spi_set_ios, }; -static struct mmc_config mmc_spi_cfg = { - .name = "MMC_SPI", - .ops = &mmc_spi_ops, - .host_caps = MMC_MODE_SPI, - .voltages = MMC_SPI_VOLTAGE, - .f_min = MMC_SPI_MIN_CLOCK, - .part_type = PART_TYPE_DOS, - .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, +static const struct udevice_id dm_mmc_spi_match[] = { + { .compatible = "mmc-spi-slot" }, + { /* sentinel */ } }; -struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode) -{ - struct mmc *mmc; - struct spi_slave *spi; - - spi = spi_setup_slave(bus, cs, speed, mode); - if (spi == NULL) - return NULL; - - mmc_spi_cfg.f_max = speed; - - mmc = mmc_create(&mmc_spi_cfg, spi); - if (mmc == NULL) { - spi_free_slave(spi); - return NULL; - } - return mmc; -} +U_BOOT_DRIVER(mmc_spi) = { + .name = "mmc_spi", + .id = UCLASS_MMC, + .of_match = dm_mmc_spi_match, + .ops = &mmc_spi_ops, + .probe = mmc_spi_probe, + .bind = mmc_spi_bind, + .priv_auto_alloc_size = sizeof(struct mmc_spi_priv), +}; diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c index c8c83c9188..02648b0f50 100644 --- a/drivers/mmc/mmc_write.c +++ b/drivers/mmc/mmc_write.c @@ -119,7 +119,7 @@ ulong mmc_berase(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt) blk += blk_r; /* Waiting for the ready status */ - if (mmc_send_status(mmc, timeout)) + if (mmc_poll_for_busy(mmc, timeout)) return 0; } @@ -177,7 +177,7 @@ static ulong mmc_write_blocks(struct mmc *mmc, lbaint_t start, } /* Waiting for the ready status */ - if (mmc_send_status(mmc, timeout)) + if (mmc_poll_for_busy(mmc, timeout)) return 0; return blkcnt; diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c index 133cdc1352..3ea7f4e173 100644 --- a/drivers/mmc/omap_hsmmc.c +++ b/drivers/mmc/omap_hsmmc.c @@ -430,7 +430,6 @@ static void omap_hsmmc_conf_bus_power(struct mmc *mmc, uint signal_voltage) writel(ac12, &mmc_base->ac12); } -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout) { int ret = -ETIMEDOUT; @@ -456,7 +455,6 @@ static int omap_hsmmc_wait_dat0(struct udevice *dev, int state, int timeout) return ret; } -#endif #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) #if CONFIG_IS_ENABLED(DM_REGULATOR) @@ -775,14 +773,6 @@ tuning_error: return ret; } #endif - -static void omap_hsmmc_send_init_stream(struct udevice *dev) -{ - struct omap_hsmmc_data *priv = dev_get_priv(dev); - struct hsmmc *mmc_base = priv->base_addr; - - mmc_init_stream(mmc_base); -} #endif static void mmc_enable_irq(struct mmc *mmc, struct mmc_cmd *cmd) @@ -1065,18 +1055,17 @@ static int omap_hsmmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, if (get_timer(0) - start > MAX_RETRY_MS) { printf("%s: timedout waiting on cmd inhibit to clear\n", __func__); + mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD); + mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC); return -ETIMEDOUT; } } writel(0xFFFFFFFF, &mmc_base->stat); - start = get_timer(0); - while (readl(&mmc_base->stat)) { - if (get_timer(0) - start > MAX_RETRY_MS) { - printf("%s: timedout waiting for STAT (%x) to clear\n", - __func__, readl(&mmc_base->stat)); - return -ETIMEDOUT; - } + if (readl(&mmc_base->stat)) { + mmc_reset_controller_fsm(mmc_base, SYSCTL_SRD); + mmc_reset_controller_fsm(mmc_base, SYSCTL_SRC); } + /* * CMDREG * CMDIDX[13:8] : Command index @@ -1522,10 +1511,7 @@ static const struct dm_mmc_ops omap_hsmmc_ops = { #ifdef MMC_SUPPORTS_TUNING .execute_tuning = omap_hsmmc_execute_tuning, #endif - .send_init_stream = omap_hsmmc_send_init_stream, -#if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) .wait_dat0 = omap_hsmmc_wait_dat0, -#endif }; #else static const struct mmc_ops omap_hsmmc_ops = { diff --git a/drivers/mmc/rpmb.c b/drivers/mmc/rpmb.c index 908f192089..33371fe562 100644 --- a/drivers/mmc/rpmb.c +++ b/drivers/mmc/rpmb.c @@ -103,7 +103,7 @@ static int mmc_rpmb_request(struct mmc *mmc, const struct s_rpmb *s, cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; cmd.cmdarg = 0; - cmd.resp_type = MMC_RSP_R1b; + cmd.resp_type = MMC_RSP_R1; data.src = (const char *)s; data.blocks = 1; @@ -327,7 +327,7 @@ static int send_write_mult_block(struct mmc *mmc, const struct s_rpmb *frm, { struct mmc_cmd cmd = { .cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK, - .resp_type = MMC_RSP_R1b, + .resp_type = MMC_RSP_R1, }; struct mmc_data data = { .src = (const void *)frm, diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index e2bb90abbd..c4e88790bc 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -12,6 +12,7 @@ #include <malloc.h> #include <mmc.h> #include <sdhci.h> +#include <dm.h> #if defined(CONFIG_FIXED_SDHCI_ALIGNED_BUFFER) void *aligned_buffer = (void *)CONFIG_FIXED_SDHCI_ALIGNED_BUFFER; @@ -590,6 +591,12 @@ static int sdhci_set_ios(struct mmc *mmc) static int sdhci_init(struct mmc *mmc) { struct sdhci_host *host = mmc->priv; +#if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_GPIO) + struct udevice *dev = mmc->dev; + + gpio_request_by_name(dev, "cd-gpio", 0, + &host->cd_gpio, GPIOD_IS_IN); +#endif sdhci_reset(host, SDHCI_RESET_ALL); @@ -624,9 +631,40 @@ int sdhci_probe(struct udevice *dev) return sdhci_init(mmc); } +int sdhci_get_cd(struct udevice *dev) +{ + struct mmc *mmc = mmc_get_mmc_dev(dev); + struct sdhci_host *host = mmc->priv; + int value; + + /* If nonremovable, assume that the card is always present. */ + if (mmc->cfg->host_caps & MMC_CAP_NONREMOVABLE) + return 1; + /* If polling, assume that the card is always present. */ + if (mmc->cfg->host_caps & MMC_CAP_NEEDS_POLL) + return 1; + +#if CONFIG_IS_ENABLED(DM_GPIO) + value = dm_gpio_get_value(&host->cd_gpio); + if (value >= 0) { + if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH) + return !value; + else + return value; + } +#endif + value = !!(sdhci_readl(host, SDHCI_PRESENT_STATE) & + SDHCI_CARD_PRESENT); + if (mmc->cfg->host_caps & MMC_CAP_CD_ACTIVE_HIGH) + return !value; + else + return value; +} + const struct dm_mmc_ops sdhci_ops = { .send_cmd = sdhci_send_command, .set_ios = sdhci_set_ios, + .get_cd = sdhci_get_cd, #ifdef MMC_SUPPORTS_TUNING .execute_tuning = sdhci_execute_tuning, #endif diff --git a/drivers/mmc/stm32_sdmmc2.c b/drivers/mmc/stm32_sdmmc2.c index ed31ca126e..867ed569eb 100644 --- a/drivers/mmc/stm32_sdmmc2.c +++ b/drivers/mmc/stm32_sdmmc2.c @@ -669,6 +669,7 @@ static int stm32_sdmmc2_probe(struct udevice *dev) switch (dev_read_u32_default(dev, "bus-width", 1)) { case 8: cfg->host_caps |= MMC_MODE_8BIT; + /* fall through */ case 4: cfg->host_caps |= MMC_MODE_4BIT; break; @@ -692,7 +693,7 @@ clk_free: return ret; } -int stm32_sdmmc_bind(struct udevice *dev) +static int stm32_sdmmc_bind(struct udevice *dev) { struct stm32_sdmmc2_plat *plat = dev_get_platdata(dev); diff --git a/drivers/mtd/nand/raw/stm32_fmc2_nand.c b/drivers/mtd/nand/raw/stm32_fmc2_nand.c index 2bb749d7f7..f3179cc21f 100644 --- a/drivers/mtd/nand/raw/stm32_fmc2_nand.c +++ b/drivers/mtd/nand/raw/stm32_fmc2_nand.c @@ -627,21 +627,16 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, struct stm32_fmc2_timings *tims = &nand->timings; unsigned long hclk = clk_get_rate(&fmc2->clk); unsigned long hclkp = FMC2_NSEC_PER_SEC / (hclk / 1000); - int tar, tclr, thiz, twait, tset_mem, tset_att, thold_mem, thold_att; - - tar = hclkp; - if (tar < sdrt->tAR_min) - tar = sdrt->tAR_min; - tims->tar = DIV_ROUND_UP(tar, hclkp) - 1; - if (tims->tar > FMC2_PCR_TIMING_MASK) - tims->tar = FMC2_PCR_TIMING_MASK; - - tclr = hclkp; - if (tclr < sdrt->tCLR_min) - tclr = sdrt->tCLR_min; - tims->tclr = DIV_ROUND_UP(tclr, hclkp) - 1; - if (tims->tclr > FMC2_PCR_TIMING_MASK) - tims->tclr = FMC2_PCR_TIMING_MASK; + unsigned long timing, tar, tclr, thiz, twait; + unsigned long tset_mem, tset_att, thold_mem, thold_att; + + tar = max_t(unsigned long, hclkp, sdrt->tAR_min); + timing = DIV_ROUND_UP(tar, hclkp) - 1; + tims->tar = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK); + + tclr = max_t(unsigned long, hclkp, sdrt->tCLR_min); + timing = DIV_ROUND_UP(tclr, hclkp) - 1; + tims->tclr = min_t(unsigned long, timing, FMC2_PCR_TIMING_MASK); tims->thiz = FMC2_THIZ; thiz = (tims->thiz + 1) * hclkp; @@ -651,18 +646,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, * tWAIT > tWP * tWAIT > tREA + tIO */ - twait = hclkp; - if (twait < sdrt->tRP_min) - twait = sdrt->tRP_min; - if (twait < sdrt->tWP_min) - twait = sdrt->tWP_min; - if (twait < sdrt->tREA_max + FMC2_TIO) - twait = sdrt->tREA_max + FMC2_TIO; - tims->twait = DIV_ROUND_UP(twait, hclkp); - if (tims->twait == 0) - tims->twait = 1; - else if (tims->twait > FMC2_PMEM_PATT_TIMING_MASK) - tims->twait = FMC2_PMEM_PATT_TIMING_MASK; + twait = max_t(unsigned long, hclkp, sdrt->tRP_min); + twait = max_t(unsigned long, twait, sdrt->tWP_min); + twait = max_t(unsigned long, twait, sdrt->tREA_max + FMC2_TIO); + timing = DIV_ROUND_UP(twait, hclkp); + tims->twait = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); /* * tSETUP_MEM > tCS - tWAIT @@ -677,20 +665,15 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, if (twait > thiz && (sdrt->tDS_min > twait - thiz) && (tset_mem < sdrt->tDS_min - (twait - thiz))) tset_mem = sdrt->tDS_min - (twait - thiz); - tims->tset_mem = DIV_ROUND_UP(tset_mem, hclkp); - if (tims->tset_mem == 0) - tims->tset_mem = 1; - else if (tims->tset_mem > FMC2_PMEM_PATT_TIMING_MASK) - tims->tset_mem = FMC2_PMEM_PATT_TIMING_MASK; + timing = DIV_ROUND_UP(tset_mem, hclkp); + tims->tset_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); /* * tHOLD_MEM > tCH * tHOLD_MEM > tREH - tSETUP_MEM * tHOLD_MEM > max(tRC, tWC) - (tSETUP_MEM + tWAIT) */ - thold_mem = hclkp; - if (thold_mem < sdrt->tCH_min) - thold_mem = sdrt->tCH_min; + thold_mem = max_t(unsigned long, hclkp, sdrt->tCH_min); if (sdrt->tREH_min > tset_mem && (thold_mem < sdrt->tREH_min - tset_mem)) thold_mem = sdrt->tREH_min - tset_mem; @@ -700,11 +683,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, if ((sdrt->tWC_min > tset_mem + twait) && (thold_mem < sdrt->tWC_min - (tset_mem + twait))) thold_mem = sdrt->tWC_min - (tset_mem + twait); - tims->thold_mem = DIV_ROUND_UP(thold_mem, hclkp); - if (tims->thold_mem == 0) - tims->thold_mem = 1; - else if (tims->thold_mem > FMC2_PMEM_PATT_TIMING_MASK) - tims->thold_mem = FMC2_PMEM_PATT_TIMING_MASK; + timing = DIV_ROUND_UP(thold_mem, hclkp); + tims->thold_mem = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); /* * tSETUP_ATT > tCS - tWAIT @@ -726,11 +706,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, if (twait > thiz && (sdrt->tDS_min > twait - thiz) && (tset_att < sdrt->tDS_min - (twait - thiz))) tset_att = sdrt->tDS_min - (twait - thiz); - tims->tset_att = DIV_ROUND_UP(tset_att, hclkp); - if (tims->tset_att == 0) - tims->tset_att = 1; - else if (tims->tset_att > FMC2_PMEM_PATT_TIMING_MASK) - tims->tset_att = FMC2_PMEM_PATT_TIMING_MASK; + timing = DIV_ROUND_UP(tset_att, hclkp); + tims->tset_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); /* * tHOLD_ATT > tALH @@ -745,17 +722,11 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, * tHOLD_ATT > tRC - (tSETUP_ATT + tWAIT) * tHOLD_ATT > tWC - (tSETUP_ATT + tWAIT) */ - thold_att = hclkp; - if (thold_att < sdrt->tALH_min) - thold_att = sdrt->tALH_min; - if (thold_att < sdrt->tCH_min) - thold_att = sdrt->tCH_min; - if (thold_att < sdrt->tCLH_min) - thold_att = sdrt->tCLH_min; - if (thold_att < sdrt->tCOH_min) - thold_att = sdrt->tCOH_min; - if (thold_att < sdrt->tDH_min) - thold_att = sdrt->tDH_min; + thold_att = max_t(unsigned long, hclkp, sdrt->tALH_min); + thold_att = max_t(unsigned long, thold_att, sdrt->tCH_min); + thold_att = max_t(unsigned long, thold_att, sdrt->tCLH_min); + thold_att = max_t(unsigned long, thold_att, sdrt->tCOH_min); + thold_att = max_t(unsigned long, thold_att, sdrt->tDH_min); if ((sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC > tset_mem) && (thold_att < sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem)) thold_att = sdrt->tWB_max + FMC2_TIO + FMC2_TSYNC - tset_mem; @@ -774,11 +745,8 @@ static void stm32_fmc2_calc_timings(struct nand_chip *chip, if ((sdrt->tWC_min > tset_att + twait) && (thold_att < sdrt->tWC_min - (tset_att + twait))) thold_att = sdrt->tWC_min - (tset_att + twait); - tims->thold_att = DIV_ROUND_UP(thold_att, hclkp); - if (tims->thold_att == 0) - tims->thold_att = 1; - else if (tims->thold_att > FMC2_PMEM_PATT_TIMING_MASK) - tims->thold_att = FMC2_PMEM_PATT_TIMING_MASK; + timing = DIV_ROUND_UP(thold_att, hclkp); + tims->thold_att = clamp_val(timing, 1, FMC2_PMEM_PATT_TIMING_MASK); } static int stm32_fmc2_setup_interface(struct mtd_info *mtd, int chipnr, @@ -932,7 +900,8 @@ static int stm32_fmc2_probe(struct udevice *dev) struct nand_ecclayout *ecclayout; struct resource resource; struct reset_ctl reset; - int oob_index, chip_cs, mem_region, ret, i; + int oob_index, chip_cs, mem_region, ret; + unsigned int i; spin_lock_init(&fmc2->controller.lock); init_waitqueue_head(&fmc2->controller.wq); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e6a4fdf30e..635f8d72c2 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -11,6 +11,29 @@ config DM_ETH This is currently implemented in net/eth-uclass.c Look in include/net.h for details. +config DM_MDIO + bool "Enable Driver Model for MDIO devices" + depends on DM_ETH && PHYLIB + help + Enable driver model for MDIO devices + + Adds UCLASS_MDIO DM class supporting MDIO buses that are probed as + stand-alone devices. Useful in particular for systems that support + DM_ETH and have a stand-alone MDIO hardware block shared by multiple + Ethernet interfaces. + This is currently implemented in net/mdio-uclass.c + Look in include/miiphy.h for details. + +config MDIO_SANDBOX + depends on DM_MDIO && SANDBOX + default y + bool "Sandbox: Mocked MDIO driver" + help + This driver implements dummy read/write/reset MDIO functions mimicking + a bus with a single PHY. + + This driver is used in for testing in test/dm/mdio.c + menuconfig NETDEVICES bool "Network device support" depends on NET diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 8d02a37896..40038427db 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -77,3 +77,4 @@ obj-y += ti/ obj-$(CONFIG_MEDIATEK_ETH) += mtk_eth.o obj-y += mscc_eswitch/ obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o +obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o diff --git a/drivers/net/macb.c b/drivers/net/macb.c index c5560a7111..a7eddd647d 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -613,10 +613,12 @@ static int macb_phy_init(struct macb_device *macb, const char *name) /* First check for GMAC and that it is GiB capable */ if (gem_is_gigabit_capable(macb)) { - lpa = macb_mdio_read(macb, MII_STAT1000); + lpa = macb_mdio_read(macb, MII_LPA); - if (lpa & (LPA_1000FULL | LPA_1000HALF)) { - duplex = ((lpa & LPA_1000FULL) ? 1 : 0); + if (lpa & (LPA_1000FULL | LPA_1000HALF | LPA_1000XFULL | + LPA_1000XHALF)) { + duplex = ((lpa & (LPA_1000FULL | LPA_1000XFULL)) ? + 1 : 0); printf("%s: link up, 1000Mbps %s-duplex (lpa: 0x%04x)\n", name, diff --git a/drivers/net/mdio_sandbox.c b/drivers/net/mdio_sandbox.c new file mode 100644 index 0000000000..07515e078c --- /dev/null +++ b/drivers/net/mdio_sandbox.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2019 + * Alex Marginean, NXP + */ + +#include <dm.h> +#include <errno.h> +#include <miiphy.h> + +#define SANDBOX_PHY_ADDR 5 +#define SANDBOX_PHY_REG 0 + +struct mdio_sandbox_priv { + int enabled; + u16 reg; +}; + +static int mdio_sandbox_read(struct udevice *dev, int addr, int devad, int reg) +{ + struct mdio_sandbox_priv *priv = dev_get_priv(dev); + + if (!priv->enabled) + return -ENODEV; + + if (addr != SANDBOX_PHY_ADDR) + return -ENODEV; + if (devad != MDIO_DEVAD_NONE) + return -ENODEV; + if (reg != SANDBOX_PHY_REG) + return -ENODEV; + + return priv->reg; +} + +static int mdio_sandbox_write(struct udevice *dev, int addr, int devad, int reg, + u16 val) +{ + struct mdio_sandbox_priv *priv = dev_get_priv(dev); + + if (!priv->enabled) + return -ENODEV; + + if (addr != SANDBOX_PHY_ADDR) + return -ENODEV; + if (devad != MDIO_DEVAD_NONE) + return -ENODEV; + if (reg != SANDBOX_PHY_REG) + return -ENODEV; + + priv->reg = val; + + return 0; +} + +static int mdio_sandbox_reset(struct udevice *dev) +{ + struct mdio_sandbox_priv *priv = dev_get_priv(dev); + + priv->reg = 0; + + return 0; +} + +static const struct mdio_ops mdio_sandbox_ops = { + .read = mdio_sandbox_read, + .write = mdio_sandbox_write, + .reset = mdio_sandbox_reset, +}; + +static int mdio_sandbox_probe(struct udevice *dev) +{ + struct mdio_sandbox_priv *priv = dev_get_priv(dev); + + priv->enabled = 1; + + return 0; +} + +static const struct udevice_id mdio_sandbox_ids[] = { + { .compatible = "sandbox,mdio" }, + { } +}; + +U_BOOT_DRIVER(mdio_sandbox) = { + .name = "mdio_sandbox", + .id = UCLASS_MDIO, + .of_match = mdio_sandbox_ids, + .probe = mdio_sandbox_probe, + .ops = &mdio_sandbox_ops, + .priv_auto_alloc_size = sizeof(struct mdio_sandbox_priv), +}; diff --git a/drivers/net/mscc_eswitch/Makefile b/drivers/net/mscc_eswitch/Makefile index 02f39a76bb..d583fe9fc4 100644 --- a/drivers/net/mscc_eswitch/Makefile +++ b/drivers/net/mscc_eswitch/Makefile @@ -1,6 +1,6 @@ -obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_xfer.o mscc_mac_table.o -obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_xfer.o mscc_mac_table.o -obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o -obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o -obj-$(CONFIG_MSCC_SERVAL_SWITCH) += serval_switch.o mscc_xfer.o mscc_mac_table.o +obj-$(CONFIG_MSCC_OCELOT_SWITCH) += ocelot_switch.o mscc_xfer.o mscc_mac_table.o mscc_miim.o +obj-$(CONFIG_MSCC_LUTON_SWITCH) += luton_switch.o mscc_xfer.o mscc_mac_table.o mscc_miim.o +obj-$(CONFIG_MSCC_JR2_SWITCH) += jr2_switch.o mscc_xfer.o mscc_miim.o +obj-$(CONFIG_MSCC_SERVALT_SWITCH) += servalt_switch.o mscc_xfer.o mscc_miim.o +obj-$(CONFIG_MSCC_SERVAL_SWITCH) += serval_switch.o mscc_xfer.o mscc_mac_table.o mscc_miim.o diff --git a/drivers/net/mscc_eswitch/jr2_switch.c b/drivers/net/mscc_eswitch/jr2_switch.c index 60d408f1c7..665517775e 100644 --- a/drivers/net/mscc_eswitch/jr2_switch.c +++ b/drivers/net/mscc_eswitch/jr2_switch.c @@ -17,20 +17,7 @@ #include <dt-bindings/mscc/jr2_data.h> #include "mscc_xfer.h" - -#define GCB_MIIM_MII_STATUS 0x0 -#define GCB_MIIM_STAT_BUSY BIT(3) -#define GCB_MIIM_MII_CMD 0x8 -#define GCB_MIIM_MII_CMD_SCAN BIT(0) -#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1) -#define GCB_MIIM_MII_CMD_OPR_READ BIT(2) -#define GCB_MIIM_MII_CMD_SINGLE_SCAN BIT(3) -#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4) -#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20) -#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25) -#define GCB_MIIM_MII_CMD_VLD BIT(31) -#define GCB_MIIM_DATA 0xC -#define GCB_MIIM_DATA_ERROR (0x3 << 16) +#include "mscc_miim.h" #define ANA_AC_RAM_CTRL_RAM_INIT 0x94358 #define ANA_AC_STAT_GLOBAL_CFG_PORT_RESET 0x94370 @@ -279,13 +266,6 @@ struct jr2_private { struct jr2_phy_port_t ports[MAX_PORT]; }; -struct jr2_miim_dev { - void __iomem *regs; - phys_addr_t miim_base; - unsigned long miim_size; - struct mii_dev *bus; -}; - static const unsigned long jr2_regs_qs[] = { [MSCC_QS_XTR_RD] = 0x8, [MSCC_QS_XTR_FLUSH] = 0x18, @@ -294,99 +274,9 @@ static const unsigned long jr2_regs_qs[] = { [MSCC_QS_INJ_CTRL] = 0x34, }; -static struct jr2_miim_dev miim[JR2_MIIM_BUS_COUNT]; +static struct mscc_miim_dev miim[JR2_MIIM_BUS_COUNT]; static int miim_count = -1; -static int mscc_miim_wait_ready(struct jr2_miim_dev *miim) -{ - unsigned long deadline; - u32 val; - - deadline = timer_get_us() + 250000; - - do { - val = readl(miim->regs + GCB_MIIM_MII_STATUS); - } while (timer_get_us() <= deadline && (val & GCB_MIIM_STAT_BUSY)); - - if (val & GCB_MIIM_STAT_BUSY) - return -ETIMEDOUT; - - return 0; -} - -static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) -{ - struct jr2_miim_dev *miim = (struct jr2_miim_dev *)bus->priv; - u32 val; - int ret; - - ret = mscc_miim_wait_ready(miim); - if (ret) - goto out; - - writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | - GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ, - miim->regs + GCB_MIIM_MII_CMD); - - ret = mscc_miim_wait_ready(miim); - if (ret) - goto out; - - val = readl(miim->regs + GCB_MIIM_DATA); - if (val & GCB_MIIM_DATA_ERROR) { - ret = -EIO; - goto out; - } - - ret = val & 0xFFFF; - out: - return ret; -} - -static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, - u16 val) -{ - struct jr2_miim_dev *miim = (struct jr2_miim_dev *)bus->priv; - int ret; - - ret = mscc_miim_wait_ready(miim); - if (ret < 0) - goto out; - - writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | - GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) | - GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD); - - out: - return ret; -} - -static struct mii_dev *jr2_mdiobus_init(phys_addr_t miim_base, - unsigned long miim_size) -{ - struct mii_dev *bus; - - bus = mdio_alloc(); - if (!bus) - return NULL; - - ++miim_count; - sprintf(bus->name, "miim-bus%d", miim_count); - - miim[miim_count].regs = ioremap(miim_base, miim_size); - miim[miim_count].miim_base = miim_base; - miim[miim_count].miim_size = miim_size; - bus->priv = &miim[miim_count]; - bus->read = mscc_miim_read; - bus->write = mscc_miim_write; - - if (mdio_register(bus)) - return NULL; - - miim[miim_count].bus = bus; - return bus; -} - static void jr2_cpu_capture_setup(struct jr2_private *priv) { /* ASM: No preamble and IFH prefix on CPU injected frames */ @@ -973,7 +863,7 @@ static int jr2_probe(struct udevice *dev) } /* Initialize miim buses */ - memset(&miim, 0x0, sizeof(struct jr2_miim_dev) * JR2_MIIM_BUS_COUNT); + memset(&miim, 0x0, sizeof(struct mscc_miim_dev) * JR2_MIIM_BUS_COUNT); /* iterate all the ports and find out on which bus they are */ i = 0; @@ -1008,7 +898,8 @@ static int jr2_probe(struct udevice *dev) /* If the bus is new then create a new bus */ if (!get_mdiobus(addr_base, addr_size)) priv->bus[miim_count] = - jr2_mdiobus_init(addr_base, addr_size); + mscc_mdiobus_init(miim, &miim_count, addr_base, + addr_size); /* Connect mdio bus with the port */ bus = get_mdiobus(addr_base, addr_size); diff --git a/drivers/net/mscc_eswitch/luton_switch.c b/drivers/net/mscc_eswitch/luton_switch.c index 94852b06e7..dffe81d873 100644 --- a/drivers/net/mscc_eswitch/luton_switch.c +++ b/drivers/net/mscc_eswitch/luton_switch.c @@ -17,18 +17,7 @@ #include "mscc_xfer.h" #include "mscc_mac_table.h" - -#define GCB_MIIM_MII_STATUS 0x0 -#define GCB_MIIM_STAT_BUSY BIT(3) -#define GCB_MIIM_MII_CMD 0x8 -#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1) -#define GCB_MIIM_MII_CMD_OPR_READ BIT(2) -#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4) -#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20) -#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25) -#define GCB_MIIM_MII_CMD_VLD BIT(31) -#define GCB_MIIM_DATA 0xC -#define GCB_MIIM_DATA_ERROR (0x2 << 16) +#include "mscc_miim.h" #define ANA_PORT_VLAN_CFG(x) (0x00 + 0x80 * (x)) #define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) @@ -189,13 +178,6 @@ struct luton_private { struct luton_phy_port_t ports[MAX_PORT]; }; -struct mscc_miim_dev { - void __iomem *regs; - phys_addr_t miim_base; - unsigned long miim_size; - struct mii_dev *bus; -}; - static const unsigned long luton_regs_qs[] = { [MSCC_QS_XTR_RD] = 0x18, [MSCC_QS_XTR_FLUSH] = 0x28, @@ -213,84 +195,6 @@ static const unsigned long luton_regs_ana_table[] = { static struct mscc_miim_dev miim[LUTON_MIIM_BUS_COUNT]; static int miim_count = -1; -static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) -{ - return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS, - GCB_MIIM_STAT_BUSY, false, 250, false); -} - -static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) -{ - struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; - u32 val; - int ret; - - ret = mscc_miim_wait_ready(miim); - if (ret) - goto out; - - writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | - GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ, - miim->regs + GCB_MIIM_MII_CMD); - - ret = mscc_miim_wait_ready(miim); - if (ret) - goto out; - - val = readl(miim->regs + GCB_MIIM_DATA); - if (val & GCB_MIIM_DATA_ERROR) { - ret = -EIO; - goto out; - } - - ret = val & 0xFFFF; - out: - return ret; -} - -static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, - u16 val) -{ - struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; - int ret; - - ret = mscc_miim_wait_ready(miim); - if (ret < 0) - goto out; - - writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | - GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) | - GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD); - out: - return ret; -} - -static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base, - unsigned long miim_size) -{ - struct mii_dev *bus; - - bus = mdio_alloc(); - if (!bus) - return NULL; - - ++miim_count; - sprintf(bus->name, "miim-bus%d", miim_count); - - miim[miim_count].regs = ioremap(miim_base, miim_size); - miim[miim_count].miim_base = miim_base; - miim[miim_count].miim_size = miim_size; - bus->priv = &miim[miim_count]; - bus->read = mscc_miim_read; - bus->write = mscc_miim_write; - - if (mdio_register(bus)) - return NULL; - - miim[miim_count].bus = bus; - return bus; -} - static void luton_stop(struct udevice *dev) { struct luton_private *priv = dev_get_priv(dev); @@ -760,7 +664,8 @@ static int luton_probe(struct udevice *dev) /* If the bus is new then create a new bus */ if (!get_mdiobus(addr_base, addr_size)) priv->bus[miim_count] = - serval_mdiobus_init(addr_base, addr_size); + mscc_mdiobus_init(miim, &miim_count, addr_base, + addr_size); /* Connect mdio bus with the port */ bus = get_mdiobus(addr_base, addr_size); diff --git a/drivers/net/mscc_eswitch/mscc_miim.c b/drivers/net/mscc_eswitch/mscc_miim.c index 419dcc1dd6..d8ee8df47b 100644 --- a/drivers/net/mscc_eswitch/mscc_miim.c +++ b/drivers/net/mscc_eswitch/mscc_miim.c @@ -72,3 +72,31 @@ int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, out: return ret; } + +struct mii_dev *mscc_mdiobus_init(struct mscc_miim_dev *miim, int *miim_count, + phys_addr_t miim_base, + unsigned long miim_size) +{ + struct mii_dev *bus; + + bus = mdio_alloc(); + + if (!bus) + return NULL; + + *miim_count += 1; + sprintf(bus->name, "miim-bus%d", *miim_count); + + miim[*miim_count].regs = ioremap(miim_base, miim_size); + miim[*miim_count].miim_base = miim_base; + miim[*miim_count].miim_size = miim_size; + bus->priv = &miim[*miim_count]; + bus->read = mscc_miim_read; + bus->write = mscc_miim_write; + + if (mdio_register(bus)) + return NULL; + + miim[*miim_count].bus = bus; + return bus; +} diff --git a/drivers/net/mscc_eswitch/mscc_miim.h b/drivers/net/mscc_eswitch/mscc_miim.h index 0e5d5e3c81..feb1f40ae5 100644 --- a/drivers/net/mscc_eswitch/mscc_miim.h +++ b/drivers/net/mscc_eswitch/mscc_miim.h @@ -3,10 +3,22 @@ * Copyright (c) 2018 Microsemi Corporation */ +#ifndef _MSCC_MIIM_H_ +#define _MSCC_MIIM_H_ + struct mscc_miim_dev { void __iomem *regs; - void __iomem *phy_regs; + phys_addr_t miim_base; + unsigned long miim_size; + struct mii_dev *bus; }; int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg); int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, u16 val); + +struct mii_dev *mscc_mdiobus_init(struct mscc_miim_dev *miim, int *miim_count, + phys_addr_t miim_base, + unsigned long miim_size); + + +#endif /* _MSCC_MIIM_H_ */ diff --git a/drivers/net/mscc_eswitch/ocelot_switch.c b/drivers/net/mscc_eswitch/ocelot_switch.c index 5c7e6961be..0ba84ab78a 100644 --- a/drivers/net/mscc_eswitch/ocelot_switch.c +++ b/drivers/net/mscc_eswitch/ocelot_switch.c @@ -17,6 +17,7 @@ #include "mscc_xfer.h" #include "mscc_mac_table.h" +#include "mscc_miim.h" #define PHY_CFG 0x0 #define PHY_CFG_ENA 0xF @@ -25,20 +26,6 @@ #define PHY_STAT 0x4 #define PHY_STAT_SUPERVISOR_COMPLETE BIT(0) -#define GCB_MIIM_MII_STATUS 0x0 -#define GCB_MIIM_STAT_BUSY BIT(3) -#define GCB_MIIM_MII_CMD 0x8 -#define GCB_MIIM_MII_CMD_SCAN BIT(0) -#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1) -#define GCB_MIIM_MII_CMD_OPR_READ BIT(2) -#define GCB_MIIM_MII_CMD_SINGLE_SCAN BIT(3) -#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4) -#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20) -#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25) -#define GCB_MIIM_MII_CMD_VLD BIT(31) -#define GCB_MIIM_DATA 0xC -#define GCB_MIIM_DATA_ERROR (0x3 << 16) - #define ANA_PORT_VLAN_CFG(x) (0x7000 + 0x100 * (x)) #define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) #define ANA_PORT_VLAN_CFG_POP_CNT(x) ((x) << 18) @@ -173,13 +160,6 @@ struct ocelot_private { struct ocelot_phy_port_t ports[MAX_PORT]; }; -struct mscc_miim_dev { - void __iomem *regs; - phys_addr_t miim_base; - unsigned long miim_size; - struct mii_dev *bus; -}; - static struct mscc_miim_dev miim[OCELOT_MIIM_BUS_COUNT]; static int miim_count = -1; @@ -209,85 +189,6 @@ static void mscc_phy_reset(void) } } -static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) -{ - return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS, - GCB_MIIM_STAT_BUSY, false, 250, false); -} - -static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) -{ - struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; - u32 val; - int ret; - - ret = mscc_miim_wait_ready(miim); - if (ret) - goto out; - - writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | - GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ, - miim->regs + GCB_MIIM_MII_CMD); - - ret = mscc_miim_wait_ready(miim); - if (ret) - goto out; - - val = readl(miim->regs + GCB_MIIM_DATA); - if (val & GCB_MIIM_DATA_ERROR) { - ret = -EIO; - goto out; - } - - ret = val & 0xFFFF; - out: - return ret; -} - -static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, - u16 val) -{ - struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; - int ret; - - ret = mscc_miim_wait_ready(miim); - if (ret < 0) - goto out; - - writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | - GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) | - GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD); - out: - return ret; -} - -static struct mii_dev *ocelot_mdiobus_init(phys_addr_t miim_base, - unsigned long miim_size) -{ - struct mii_dev *bus; - - bus = mdio_alloc(); - - if (!bus) - return NULL; - - ++miim_count; - sprintf(bus->name, "miim-bus%d", miim_count); - - miim[miim_count].regs = ioremap(miim_base, miim_size); - miim[miim_count].miim_base = miim_base; - miim[miim_count].miim_size = miim_size; - bus->priv = &miim[miim_count]; - bus->read = mscc_miim_read; - bus->write = mscc_miim_write; - - if (mdio_register(bus)) - return NULL; - - miim[miim_count].bus = bus; - return bus; -} - __weak void mscc_switch_reset(void) { } @@ -682,7 +583,8 @@ static int ocelot_probe(struct udevice *dev) /* If the bus is new then create a new bus */ if (!get_mdiobus(addr_base, addr_size)) priv->bus[miim_count] = - ocelot_mdiobus_init(addr_base, addr_size); + mscc_mdiobus_init(miim, &miim_count, addr_base, + addr_size); /* Connect mdio bus with the port */ bus = get_mdiobus(addr_base, addr_size); diff --git a/drivers/net/mscc_eswitch/serval_switch.c b/drivers/net/mscc_eswitch/serval_switch.c index 2559f5d0cd..1a21360a96 100644 --- a/drivers/net/mscc_eswitch/serval_switch.c +++ b/drivers/net/mscc_eswitch/serval_switch.c @@ -17,18 +17,7 @@ #include "mscc_xfer.h" #include "mscc_mac_table.h" - -#define GCB_MIIM_MII_STATUS 0x0 -#define GCB_MIIM_STAT_BUSY BIT(3) -#define GCB_MIIM_MII_CMD 0x8 -#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1) -#define GCB_MIIM_MII_CMD_OPR_READ BIT(2) -#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4) -#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20) -#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25) -#define GCB_MIIM_MII_CMD_VLD BIT(31) -#define GCB_MIIM_DATA 0xC -#define GCB_MIIM_DATA_ERROR (0x2 << 16) +#include "mscc_miim.h" #define ANA_PORT_VLAN_CFG(x) (0xc000 + 0x100 * (x)) #define ANA_PORT_VLAN_CFG_AWARE_ENA BIT(20) @@ -156,13 +145,6 @@ struct serval_private { struct serval_phy_port_t ports[MAX_PORT]; }; -struct mscc_miim_dev { - void __iomem *regs; - phys_addr_t miim_base; - unsigned long miim_size; - struct mii_dev *bus; -}; - static const unsigned long serval_regs_qs[] = { [MSCC_QS_XTR_RD] = 0x8, [MSCC_QS_XTR_FLUSH] = 0x18, @@ -180,84 +162,6 @@ static const unsigned long serval_regs_ana_table[] = { static struct mscc_miim_dev miim[SERVAL_MIIM_BUS_COUNT]; static int miim_count = -1; -static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) -{ - return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS, - GCB_MIIM_STAT_BUSY, false, 250, false); -} - -static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) -{ - struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; - u32 val; - int ret; - - ret = mscc_miim_wait_ready(miim); - if (ret) - goto out; - - writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | - GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ, - miim->regs + GCB_MIIM_MII_CMD); - - ret = mscc_miim_wait_ready(miim); - if (ret) - goto out; - - val = readl(miim->regs + GCB_MIIM_DATA); - if (val & GCB_MIIM_DATA_ERROR) { - ret = -EIO; - goto out; - } - - ret = val & 0xFFFF; - out: - return ret; -} - -static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, - u16 val) -{ - struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; - int ret; - - ret = mscc_miim_wait_ready(miim); - if (ret < 0) - goto out; - - writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | - GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) | - GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD); - out: - return ret; -} - -static struct mii_dev *serval_mdiobus_init(phys_addr_t miim_base, - unsigned long miim_size) -{ - struct mii_dev *bus; - - bus = mdio_alloc(); - if (!bus) - return NULL; - - ++miim_count; - sprintf(bus->name, "miim-bus%d", miim_count); - - miim[miim_count].regs = ioremap(miim_base, miim_size); - miim[miim_count].miim_base = miim_base; - miim[miim_count].miim_size = miim_size; - bus->priv = &miim[miim_count]; - bus->read = mscc_miim_read; - bus->write = mscc_miim_write; - - if (mdio_register(bus)) - return NULL; - - miim[miim_count].bus = bus; - return bus; -} - static void serval_cpu_capture_setup(struct serval_private *priv) { int i; @@ -356,8 +260,6 @@ static void serdes_write(void __iomem *base, u32 addr) do { data = readl(base + HSIO_MCB_SERDES1G_CFG); } while (data & HSIO_MCB_SERDES1G_CFG_WR_ONE_SHOT); - - mdelay(100); } static void serdes1g_setup(void __iomem *base, uint32_t addr, @@ -636,7 +538,8 @@ static int serval_probe(struct udevice *dev) /* If the bus is new then create a new bus */ if (!get_mdiobus(addr_base, addr_size)) priv->bus[miim_count] = - serval_mdiobus_init(addr_base, addr_size); + mscc_mdiobus_init(miim, &miim_count, addr_base, + addr_size); /* Connect mdio bus with the port */ bus = get_mdiobus(addr_base, addr_size); diff --git a/drivers/net/mscc_eswitch/servalt_switch.c b/drivers/net/mscc_eswitch/servalt_switch.c index 995c62309d..d20ec49d56 100644 --- a/drivers/net/mscc_eswitch/servalt_switch.c +++ b/drivers/net/mscc_eswitch/servalt_switch.c @@ -16,18 +16,7 @@ #include <wait_bit.h> #include "mscc_xfer.h" - -#define GCB_MIIM_MII_STATUS 0x0 -#define GCB_MIIM_STAT_BUSY BIT(3) -#define GCB_MIIM_MII_CMD 0x8 -#define GCB_MIIM_MII_CMD_OPR_WRITE BIT(1) -#define GCB_MIIM_MII_CMD_OPR_READ BIT(2) -#define GCB_MIIM_MII_CMD_WRDATA(x) ((x) << 4) -#define GCB_MIIM_MII_CMD_REGAD(x) ((x) << 20) -#define GCB_MIIM_MII_CMD_PHYAD(x) ((x) << 25) -#define GCB_MIIM_MII_CMD_VLD BIT(31) -#define GCB_MIIM_DATA 0xC -#define GCB_MIIM_DATA_ERROR (0x3 << 16) +#include "mscc_miim.h" #define PHY_CFG 0x0 #define PHY_CFG_ENA 0x3 @@ -134,13 +123,6 @@ struct servalt_private { struct servalt_phy_port_t ports[MAX_PORT]; }; -struct mscc_miim_dev { - void __iomem *regs; - phys_addr_t miim_base; - unsigned long miim_size; - struct mii_dev *bus; -}; - static const unsigned long servalt_regs_qs[] = { [MSCC_QS_XTR_RD] = 0x8, [MSCC_QS_XTR_FLUSH] = 0x18, @@ -152,85 +134,6 @@ static const unsigned long servalt_regs_qs[] = { static struct mscc_miim_dev miim[SERVALT_MIIM_BUS_COUNT]; static int miim_count = -1; -static int mscc_miim_wait_ready(struct mscc_miim_dev *miim) -{ - return wait_for_bit_le32(miim->regs + GCB_MIIM_MII_STATUS, - GCB_MIIM_STAT_BUSY, false, 250, false); -} - -static int mscc_miim_read(struct mii_dev *bus, int addr, int devad, int reg) -{ - struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; - u32 val; - int ret; - - ret = mscc_miim_wait_ready(miim); - if (ret) - goto out; - - writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | - GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_OPR_READ, - miim->regs + GCB_MIIM_MII_CMD); - - ret = mscc_miim_wait_ready(miim); - if (ret) - goto out; - - val = readl(miim->regs + GCB_MIIM_DATA); - if (val & GCB_MIIM_DATA_ERROR) { - ret = -EIO; - goto out; - } - - ret = val & 0xFFFF; -out: - return ret; -} - -static int mscc_miim_write(struct mii_dev *bus, int addr, int devad, int reg, - u16 val) -{ - struct mscc_miim_dev *miim = (struct mscc_miim_dev *)bus->priv; - int ret; - - ret = mscc_miim_wait_ready(miim); - if (ret < 0) - goto out; - - writel(GCB_MIIM_MII_CMD_VLD | GCB_MIIM_MII_CMD_PHYAD(addr) | - GCB_MIIM_MII_CMD_REGAD(reg) | GCB_MIIM_MII_CMD_WRDATA(val) | - GCB_MIIM_MII_CMD_OPR_WRITE, miim->regs + GCB_MIIM_MII_CMD); - -out: - return ret; -} - -static struct mii_dev *servalt_mdiobus_init(phys_addr_t miim_base, - unsigned long miim_size) -{ - struct mii_dev *bus; - - bus = mdio_alloc(); - if (!bus) - return NULL; - - ++miim_count; - sprintf(bus->name, "miim-bus%d", miim_count); - - miim[miim_count].regs = ioremap(miim_base, miim_size); - miim[miim_count].miim_base = miim_base; - miim[miim_count].miim_size = miim_size; - bus->priv = &miim[miim_count]; - bus->read = mscc_miim_read; - bus->write = mscc_miim_write; - - if (mdio_register(bus)) - return NULL; - - miim[miim_count].bus = bus; - return bus; -} - static void mscc_phy_reset(void) { writel(0, BASE_DEVCPU_GCB + GCB_PHY_CFG + PHY_CFG); @@ -564,7 +467,8 @@ static int servalt_probe(struct udevice *dev) /* If the bus is new then create a new bus */ if (!get_mdiobus(addr_base, addr_size)) priv->bus[miim_count] = - servalt_mdiobus_init(addr_base, addr_size); + mscc_mdiobus_init(miim, &miim_count, addr_base, + addr_size); /* Connect mdio bus with the port */ bus = get_mdiobus(addr_base, addr_size); diff --git a/drivers/net/phy/cortina.c b/drivers/net/phy/cortina.c index a04a118f90..ec81dab3f6 100644 --- a/drivers/net/phy/cortina.c +++ b/drivers/net/phy/cortina.c @@ -176,8 +176,13 @@ void cs4340_upload_firmware(struct phy_device *phydev) printf("MMC read: dev # %u, block # %u, count %u ...\n", dev, blk, cnt); mmc_init(mmc); +#ifdef CONFIG_BLK + (void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt, + addr); +#else (void)mmc->block_dev.block_read(&mmc->block_dev, blk, cnt, addr); +#endif } #endif diff --git a/drivers/net/phy/ti.c b/drivers/net/phy/ti.c index 25f1332ca9..7509936465 100644 --- a/drivers/net/phy/ti.c +++ b/drivers/net/phy/ti.c @@ -103,7 +103,7 @@ struct dp83867_private { int io_impedance; bool rxctrl_strap_quirk; int port_mirroring; - int clk_output_sel; + unsigned int clk_output_sel; }; static int dp83867_config_port_mirroring(struct phy_device *phydev) @@ -136,17 +136,11 @@ static int dp83867_of_init(struct phy_device *phydev) ofnode node; u16 val; - /* Optional configuration */ - node = phy_get_ofnode(phydev); if (!ofnode_valid(node)) return -EINVAL; - /* - * Keep the default value if ti,clk-output-sel is not set - * or to high - */ - + /* Keep the default value if ti,clk-output-sel is not set */ dp83867->clk_output_sel = ofnode_read_u32_default(node, "ti,clk-output-sel", DP83867_CLK_O_SEL_REF_CLK); @@ -162,14 +156,14 @@ static int dp83867_of_init(struct phy_device *phydev) dp83867->rxctrl_strap_quirk = true; dp83867->rx_id_delay = ofnode_read_u32_default(node, "ti,rx-internal-delay", - -1); + DEFAULT_RX_ID_DELAY); dp83867->tx_id_delay = ofnode_read_u32_default(node, "ti,tx-internal-delay", - -1); + DEFAULT_TX_ID_DELAY); dp83867->fifo_depth = ofnode_read_u32_default(node, "ti,fifo-depth", - -1); + DEFAULT_FIFO_DEPTH); if (ofnode_read_bool(node, "enet-phy-lane-swap")) dp83867->port_mirroring = DP83867_PORT_MIRRORING_EN; diff --git a/drivers/net/ti/Kconfig b/drivers/net/ti/Kconfig index 82bc9f5d03..ecf642de10 100644 --- a/drivers/net/ti/Kconfig +++ b/drivers/net/ti/Kconfig @@ -18,3 +18,11 @@ config DRIVER_TI_KEYSTONE_NET bool "TI Keystone 2 Ethernet" help This driver supports the TI Keystone 2 Ethernet subsystem + +config TI_AM65_CPSW_NUSS + bool "TI K3 AM65x MCU CPSW Nuss Ethernet controller driver" + depends on ARCH_K3 + select PHYLIB + help + This driver supports TI K3 MCU CPSW Nuss Ethernet controller + in Texas Instruments K3 AM65x SoCs. diff --git a/drivers/net/ti/Makefile b/drivers/net/ti/Makefile index ee3e4eb5d6..8d3808bb4b 100644 --- a/drivers/net/ti/Makefile +++ b/drivers/net/ti/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o cpsw-common.o cpsw_mdio.o obj-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o obj-$(CONFIG_DRIVER_TI_KEYSTONE_NET) += keystone_net.o cpsw_mdio.o +obj-$(CONFIG_TI_AM65_CPSW_NUSS) += am65-cpsw-nuss.o cpsw_mdio.o diff --git a/drivers/net/ti/am65-cpsw-nuss.c b/drivers/net/ti/am65-cpsw-nuss.c new file mode 100644 index 0000000000..e11fbdeed3 --- /dev/null +++ b/drivers/net/ti/am65-cpsw-nuss.c @@ -0,0 +1,792 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Texas Instruments K3 AM65 Ethernet Switch SubSystem Driver + * + * Copyright (C) 2019, Texas Instruments, Incorporated + * + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/processor.h> +#include <clk.h> +#include <dm.h> +#include <dm/lists.h> +#include <dma-uclass.h> +#include <dm/of_access.h> +#include <miiphy.h> +#include <net.h> +#include <phy.h> +#include <power-domain.h> +#include <linux/soc/ti/ti-udma.h> + +#include "cpsw_mdio.h" + +#define AM65_CPSW_CPSWNU_MAX_PORTS 2 + +#define AM65_CPSW_SS_BASE 0x0 +#define AM65_CPSW_SGMII_BASE 0x100 +#define AM65_CPSW_MDIO_BASE 0xf00 +#define AM65_CPSW_XGMII_BASE 0x2100 +#define AM65_CPSW_CPSW_NU_BASE 0x20000 +#define AM65_CPSW_CPSW_NU_ALE_BASE 0x1e000 + +#define AM65_CPSW_CPSW_NU_PORTS_OFFSET 0x1000 +#define AM65_CPSW_CPSW_NU_PORT_MACSL_OFFSET 0x330 + +#define AM65_CPSW_MDIO_BUS_FREQ_DEF 1000000 + +#define AM65_CPSW_CTL_REG 0x4 +#define AM65_CPSW_STAT_PORT_EN_REG 0x14 +#define AM65_CPSW_PTYPE_REG 0x18 + +#define AM65_CPSW_CTL_REG_P0_ENABLE BIT(2) +#define AM65_CPSW_CTL_REG_P0_TX_CRC_REMOVE BIT(13) +#define AM65_CPSW_CTL_REG_P0_RX_PAD BIT(14) + +#define AM65_CPSW_P0_FLOW_ID_REG 0x8 +#define AM65_CPSW_PN_RX_MAXLEN_REG 0x24 +#define AM65_CPSW_PN_REG_SA_L 0x308 +#define AM65_CPSW_PN_REG_SA_H 0x30c + +#define AM65_CPSW_ALE_CTL_REG 0x8 +#define AM65_CPSW_ALE_CTL_REG_ENABLE BIT(31) +#define AM65_CPSW_ALE_CTL_REG_RESET_TBL BIT(30) +#define AM65_CPSW_ALE_CTL_REG_BYPASS BIT(4) +#define AM65_CPSW_ALE_PN_CTL_REG(x) (0x40 + (x) * 4) +#define AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD 0x3 +#define AM65_CPSW_ALE_PN_CTL_REG_MAC_ONLY BIT(11) + +#define AM65_CPSW_MACSL_CTL_REG 0x0 +#define AM65_CPSW_MACSL_CTL_REG_IFCTL_A BIT(15) +#define AM65_CPSW_MACSL_CTL_REG_GIG BIT(7) +#define AM65_CPSW_MACSL_CTL_REG_GMII_EN BIT(5) +#define AM65_CPSW_MACSL_CTL_REG_LOOPBACK BIT(1) +#define AM65_CPSW_MACSL_CTL_REG_FULL_DUPLEX BIT(0) +#define AM65_CPSW_MACSL_RESET_REG 0x8 +#define AM65_CPSW_MACSL_RESET_REG_RESET BIT(0) +#define AM65_CPSW_MACSL_STATUS_REG 0x4 +#define AM65_CPSW_MACSL_RESET_REG_PN_IDLE BIT(31) +#define AM65_CPSW_MACSL_RESET_REG_PN_E_IDLE BIT(30) +#define AM65_CPSW_MACSL_RESET_REG_PN_P_IDLE BIT(29) +#define AM65_CPSW_MACSL_RESET_REG_PN_TX_IDLE BIT(28) +#define AM65_CPSW_MACSL_RESET_REG_IDLE_MASK \ + (AM65_CPSW_MACSL_RESET_REG_PN_IDLE | \ + AM65_CPSW_MACSL_RESET_REG_PN_E_IDLE | \ + AM65_CPSW_MACSL_RESET_REG_PN_P_IDLE | \ + AM65_CPSW_MACSL_RESET_REG_PN_TX_IDLE) + +#define AM65_CPSW_CPPI_PKT_TYPE 0x7 + +struct am65_cpsw_port { + fdt_addr_t port_base; + fdt_addr_t macsl_base; + bool disabled; + u32 mac_control; +}; + +struct am65_cpsw_common { + struct udevice *dev; + fdt_addr_t ss_base; + fdt_addr_t cpsw_base; + fdt_addr_t mdio_base; + fdt_addr_t ale_base; + fdt_addr_t gmii_sel; + fdt_addr_t mac_efuse; + + struct clk fclk; + struct power_domain pwrdmn; + + u32 port_num; + struct am65_cpsw_port ports[AM65_CPSW_CPSWNU_MAX_PORTS]; + u32 rflow_id_base; + + struct mii_dev *bus; + u32 bus_freq; + + struct dma dma_tx; + struct dma dma_rx; + u32 rx_next; + u32 rx_pend; + bool started; +}; + +struct am65_cpsw_priv { + struct udevice *dev; + struct am65_cpsw_common *cpsw_common; + u32 port_id; + + struct phy_device *phydev; + bool has_phy; + ofnode phy_node; + u32 phy_addr; +}; + +#ifdef PKTSIZE_ALIGN +#define UDMA_RX_BUF_SIZE PKTSIZE_ALIGN +#else +#define UDMA_RX_BUF_SIZE ALIGN(1522, ARCH_DMA_MINALIGN) +#endif + +#ifdef PKTBUFSRX +#define UDMA_RX_DESC_NUM PKTBUFSRX +#else +#define UDMA_RX_DESC_NUM 4 +#endif + +#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \ + ((mac)[2] << 16) | ((mac)[3] << 24)) +#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8)) + +static void am65_cpsw_set_sl_mac(struct am65_cpsw_port *slave, + unsigned char *addr) +{ + writel(mac_hi(addr), + slave->port_base + AM65_CPSW_PN_REG_SA_H); + writel(mac_lo(addr), + slave->port_base + AM65_CPSW_PN_REG_SA_L); +} + +int am65_cpsw_macsl_reset(struct am65_cpsw_port *slave) +{ + u32 i = 100; + + /* Set the soft reset bit */ + writel(AM65_CPSW_MACSL_RESET_REG_RESET, + slave->macsl_base + AM65_CPSW_MACSL_RESET_REG); + + while ((readl(slave->macsl_base + AM65_CPSW_MACSL_RESET_REG) & + AM65_CPSW_MACSL_RESET_REG_RESET) && i--) + cpu_relax(); + + /* Timeout on the reset */ + return i; +} + +static int am65_cpsw_macsl_wait_for_idle(struct am65_cpsw_port *slave) +{ + u32 i = 100; + + while ((readl(slave->macsl_base + AM65_CPSW_MACSL_STATUS_REG) & + AM65_CPSW_MACSL_RESET_REG_IDLE_MASK) && i--) + cpu_relax(); + + return i; +} + +static int am65_cpsw_update_link(struct am65_cpsw_priv *priv) +{ + struct am65_cpsw_common *common = priv->cpsw_common; + struct am65_cpsw_port *port = &common->ports[priv->port_id]; + struct phy_device *phy = priv->phydev; + u32 mac_control = 0; + + if (phy->link) { /* link up */ + mac_control = /*AM65_CPSW_MACSL_CTL_REG_LOOPBACK |*/ + AM65_CPSW_MACSL_CTL_REG_GMII_EN; + if (phy->speed == 1000) + mac_control |= AM65_CPSW_MACSL_CTL_REG_GIG; + if (phy->duplex == DUPLEX_FULL) + mac_control |= AM65_CPSW_MACSL_CTL_REG_FULL_DUPLEX; + if (phy->speed == 100) + mac_control |= AM65_CPSW_MACSL_CTL_REG_IFCTL_A; + } + + if (mac_control == port->mac_control) + goto out; + + if (mac_control) { + printf("link up on port %d, speed %d, %s duplex\n", + priv->port_id, phy->speed, + (phy->duplex == DUPLEX_FULL) ? "full" : "half"); + } else { + printf("link down on port %d\n", priv->port_id); + } + + writel(mac_control, port->macsl_base + AM65_CPSW_MACSL_CTL_REG); + port->mac_control = mac_control; + +out: + return phy->link; +} + +#define AM65_GMII_SEL_MODE_MII 0 +#define AM65_GMII_SEL_MODE_RMII 1 +#define AM65_GMII_SEL_MODE_RGMII 2 + +#define AM65_GMII_SEL_RGMII_IDMODE BIT(4) + +static void am65_cpsw_gmii_sel_k3(struct am65_cpsw_priv *priv, + phy_interface_t phy_mode, int slave) +{ + struct am65_cpsw_common *common = priv->cpsw_common; + u32 reg; + u32 mode = 0; + bool rgmii_id = false; + + reg = readl(common->gmii_sel); + + dev_dbg(common->dev, "old gmii_sel: %08x\n", reg); + + switch (phy_mode) { + case PHY_INTERFACE_MODE_RMII: + mode = AM65_GMII_SEL_MODE_RMII; + break; + + case PHY_INTERFACE_MODE_RGMII: + mode = AM65_GMII_SEL_MODE_RGMII; + break; + + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + mode = AM65_GMII_SEL_MODE_RGMII; + rgmii_id = true; + break; + + default: + dev_warn(common->dev, + "Unsupported PHY mode: %u. Defaulting to MII.\n", + phy_mode); + /* fallthrough */ + case PHY_INTERFACE_MODE_MII: + mode = AM65_GMII_SEL_MODE_MII; + break; + }; + + if (rgmii_id) + mode |= AM65_GMII_SEL_RGMII_IDMODE; + + reg = mode; + dev_dbg(common->dev, "gmii_sel PHY mode: %u, new gmii_sel: %08x\n", + phy_mode, reg); + writel(reg, common->gmii_sel); + + reg = readl(common->gmii_sel); + if (reg != mode) + dev_err(common->dev, + "gmii_sel PHY mode NOT SET!: requested: %08x, gmii_sel: %08x\n", + mode, reg); +} + +static int am65_cpsw_start(struct udevice *dev) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct am65_cpsw_priv *priv = dev_get_priv(dev); + struct am65_cpsw_common *common = priv->cpsw_common; + struct am65_cpsw_port *port = &common->ports[priv->port_id]; + struct am65_cpsw_port *port0 = &common->ports[0]; + int ret, i; + + ret = power_domain_on(&common->pwrdmn); + if (ret) { + dev_err(dev, "power_domain_on() failed %d\n", ret); + goto out; + } + + ret = clk_enable(&common->fclk); + if (ret) { + dev_err(dev, "clk enabled failed %d\n", ret); + goto err_off_pwrdm; + } + + common->rx_next = 0; + common->rx_pend = 0; + ret = dma_get_by_name(common->dev, "tx0", &common->dma_tx); + if (ret) { + dev_err(dev, "TX dma get failed %d\n", ret); + goto err_off_clk; + } + ret = dma_get_by_name(common->dev, "rx", &common->dma_rx); + if (ret) { + dev_err(dev, "RX dma get failed %d\n", ret); + goto err_free_tx; + } + + for (i = 0; i < UDMA_RX_DESC_NUM; i++) { + ret = dma_prepare_rcv_buf(&common->dma_rx, + net_rx_packets[i], + UDMA_RX_BUF_SIZE); + if (ret) { + dev_err(dev, "RX dma add buf failed %d\n", ret); + goto err_free_tx; + } + } + + ret = dma_enable(&common->dma_tx); + if (ret) { + dev_err(dev, "TX dma_enable failed %d\n", ret); + goto err_free_rx; + } + ret = dma_enable(&common->dma_rx); + if (ret) { + dev_err(dev, "RX dma_enable failed %d\n", ret); + goto err_dis_tx; + } + + /* Control register */ + writel(AM65_CPSW_CTL_REG_P0_ENABLE | + AM65_CPSW_CTL_REG_P0_TX_CRC_REMOVE | + AM65_CPSW_CTL_REG_P0_RX_PAD, + common->cpsw_base + AM65_CPSW_CTL_REG); + + /* disable priority elevation */ + writel(0, common->cpsw_base + AM65_CPSW_PTYPE_REG); + + /* enable statistics */ + writel(BIT(0) | BIT(priv->port_id), + common->cpsw_base + AM65_CPSW_STAT_PORT_EN_REG); + + /* Port 0 length register */ + writel(PKTSIZE_ALIGN, port0->port_base + AM65_CPSW_PN_RX_MAXLEN_REG); + + /* set base flow_id */ + writel(common->rflow_id_base, + port0->port_base + AM65_CPSW_P0_FLOW_ID_REG); + + /* Reset and enable the ALE */ + writel(AM65_CPSW_ALE_CTL_REG_ENABLE | AM65_CPSW_ALE_CTL_REG_RESET_TBL | + AM65_CPSW_ALE_CTL_REG_BYPASS, + common->ale_base + AM65_CPSW_ALE_CTL_REG); + + /* port 0 put into forward mode */ + writel(AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD, + common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0)); + + /* PORT x configuration */ + + /* Port x Max length register */ + writel(PKTSIZE_ALIGN, port->port_base + AM65_CPSW_PN_RX_MAXLEN_REG); + + /* Port x set mac */ + am65_cpsw_set_sl_mac(port, pdata->enetaddr); + + /* Port x ALE: mac_only, Forwarding */ + writel(AM65_CPSW_ALE_PN_CTL_REG_MAC_ONLY | + AM65_CPSW_ALE_PN_CTL_REG_MODE_FORWARD, + common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id)); + + port->mac_control = 0; + if (!am65_cpsw_macsl_reset(port)) { + dev_err(dev, "mac_sl reset failed\n"); + ret = -EFAULT; + goto err_dis_rx; + } + + ret = phy_startup(priv->phydev); + if (ret) { + dev_err(dev, "phy_startup failed\n"); + goto err_dis_rx; + } + + ret = am65_cpsw_update_link(priv); + if (!ret) { + ret = -ENODEV; + goto err_phy_shutdown; + } + + common->started = true; + + return 0; + +err_phy_shutdown: + phy_shutdown(priv->phydev); +err_dis_rx: + /* disable ports */ + writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id)); + writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0)); + if (!am65_cpsw_macsl_wait_for_idle(port)) + dev_err(dev, "mac_sl idle timeout\n"); + writel(0, port->macsl_base + AM65_CPSW_MACSL_CTL_REG); + writel(0, common->ale_base + AM65_CPSW_ALE_CTL_REG); + writel(0, common->cpsw_base + AM65_CPSW_CTL_REG); + + dma_disable(&common->dma_rx); +err_dis_tx: + dma_disable(&common->dma_tx); +err_free_rx: + dma_free(&common->dma_rx); +err_free_tx: + dma_free(&common->dma_tx); +err_off_clk: + clk_disable(&common->fclk); +err_off_pwrdm: + power_domain_off(&common->pwrdmn); +out: + dev_err(dev, "%s end error\n", __func__); + + return ret; +} + +static int am65_cpsw_send(struct udevice *dev, void *packet, int length) +{ + struct am65_cpsw_priv *priv = dev_get_priv(dev); + struct am65_cpsw_common *common = priv->cpsw_common; + struct ti_udma_drv_packet_data packet_data; + int ret; + + packet_data.pkt_type = AM65_CPSW_CPPI_PKT_TYPE; + packet_data.dest_tag = priv->port_id; + ret = dma_send(&common->dma_tx, packet, length, &packet_data); + if (ret) { + dev_err(dev, "TX dma_send failed %d\n", ret); + return ret; + } + + return 0; +} + +static int am65_cpsw_recv(struct udevice *dev, int flags, uchar **packetp) +{ + struct am65_cpsw_priv *priv = dev_get_priv(dev); + struct am65_cpsw_common *common = priv->cpsw_common; + + /* try to receive a new packet */ + return dma_receive(&common->dma_rx, (void **)packetp, NULL); +} + +static int am65_cpsw_free_pkt(struct udevice *dev, uchar *packet, int length) +{ + struct am65_cpsw_priv *priv = dev_get_priv(dev); + struct am65_cpsw_common *common = priv->cpsw_common; + int ret; + + if (length > 0) { + u32 pkt = common->rx_next % UDMA_RX_DESC_NUM; + + ret = dma_prepare_rcv_buf(&common->dma_rx, + net_rx_packets[pkt], + UDMA_RX_BUF_SIZE); + if (ret) + dev_err(dev, "RX dma free_pkt failed %d\n", ret); + common->rx_next++; + } + + return 0; +} + +static void am65_cpsw_stop(struct udevice *dev) +{ + struct am65_cpsw_priv *priv = dev_get_priv(dev); + struct am65_cpsw_common *common = priv->cpsw_common; + struct am65_cpsw_port *port = &common->ports[priv->port_id]; + + if (!common->started) + return; + + phy_shutdown(priv->phydev); + + writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(priv->port_id)); + writel(0, common->ale_base + AM65_CPSW_ALE_PN_CTL_REG(0)); + if (!am65_cpsw_macsl_wait_for_idle(port)) + dev_err(dev, "mac_sl idle timeout\n"); + writel(0, port->macsl_base + AM65_CPSW_MACSL_CTL_REG); + writel(0, common->ale_base + AM65_CPSW_ALE_CTL_REG); + writel(0, common->cpsw_base + AM65_CPSW_CTL_REG); + + dma_disable(&common->dma_tx); + dma_free(&common->dma_tx); + + dma_disable(&common->dma_rx); + dma_free(&common->dma_rx); + + common->started = false; +} + +static int am65_cpsw_read_rom_hwaddr(struct udevice *dev) +{ + struct am65_cpsw_priv *priv = dev_get_priv(dev); + struct am65_cpsw_common *common = priv->cpsw_common; + struct eth_pdata *pdata = dev_get_platdata(dev); + u32 mac_hi, mac_lo; + + if (common->mac_efuse == FDT_ADDR_T_NONE) + return -1; + + mac_lo = readl(common->mac_efuse); + mac_hi = readl(common->mac_efuse + 4); + pdata->enetaddr[0] = (mac_hi >> 8) & 0xff; + pdata->enetaddr[1] = mac_hi & 0xff; + pdata->enetaddr[2] = (mac_lo >> 24) & 0xff; + pdata->enetaddr[3] = (mac_lo >> 16) & 0xff; + pdata->enetaddr[4] = (mac_lo >> 8) & 0xff; + pdata->enetaddr[5] = mac_lo & 0xff; + + return 0; +} + +static const struct eth_ops am65_cpsw_ops = { + .start = am65_cpsw_start, + .send = am65_cpsw_send, + .recv = am65_cpsw_recv, + .free_pkt = am65_cpsw_free_pkt, + .stop = am65_cpsw_stop, + .read_rom_hwaddr = am65_cpsw_read_rom_hwaddr, +}; + +static int am65_cpsw_mdio_init(struct udevice *dev) +{ + struct am65_cpsw_priv *priv = dev_get_priv(dev); + struct am65_cpsw_common *cpsw_common = priv->cpsw_common; + + if (!priv->has_phy || cpsw_common->bus) + return 0; + + cpsw_common->bus = cpsw_mdio_init(dev->name, + cpsw_common->mdio_base, + cpsw_common->bus_freq, + clk_get_rate(&cpsw_common->fclk)); + if (!cpsw_common->bus) + return -EFAULT; + + return 0; +} + +static int am65_cpsw_phy_init(struct udevice *dev) +{ + struct am65_cpsw_priv *priv = dev_get_priv(dev); + struct am65_cpsw_common *cpsw_common = priv->cpsw_common; + struct eth_pdata *pdata = dev_get_platdata(dev); + struct phy_device *phydev; + u32 supported = PHY_GBIT_FEATURES; + int ret; + + phydev = phy_connect(cpsw_common->bus, + priv->phy_addr, + priv->dev, + pdata->phy_interface); + + if (!phydev) { + dev_err(dev, "phy_connect() failed\n"); + return -ENODEV; + } + + phydev->supported &= supported; + if (pdata->max_speed) { + ret = phy_set_supported(phydev, pdata->max_speed); + if (ret) + return ret; + } + phydev->advertising = phydev->supported; + + if (ofnode_valid(priv->phy_node)) + phydev->node = priv->phy_node; + + priv->phydev = phydev; + ret = phy_config(phydev); + if (ret < 0) + pr_err("phy_config() failed: %d", ret); + + return ret; +} + +static int am65_cpsw_ofdata_parse_phy(struct udevice *dev, ofnode port_np) +{ + struct eth_pdata *pdata = dev_get_platdata(dev); + struct am65_cpsw_priv *priv = dev_get_priv(dev); + struct ofnode_phandle_args out_args; + const char *phy_mode; + int ret = 0; + + phy_mode = ofnode_read_string(port_np, "phy-mode"); + if (phy_mode) { + pdata->phy_interface = + phy_get_interface_by_name(phy_mode); + if (pdata->phy_interface == -1) { + dev_err(dev, "Invalid PHY mode '%s', port %u\n", + phy_mode, priv->port_id); + ret = -EINVAL; + goto out; + } + } + + ofnode_read_u32(port_np, "max-speed", (u32 *)&pdata->max_speed); + if (pdata->max_speed) + dev_err(dev, "Port %u speed froced to %uMbit\n", + priv->port_id, pdata->max_speed); + + priv->has_phy = true; + ret = ofnode_parse_phandle_with_args(port_np, "phy-handle", + NULL, 0, 0, &out_args); + if (ret) { + dev_err(dev, "can't parse phy-handle port %u (%d)\n", + priv->port_id, ret); + priv->has_phy = false; + ret = 0; + } + + priv->phy_node = out_args.node; + if (priv->has_phy) { + ret = ofnode_read_u32(priv->phy_node, "reg", &priv->phy_addr); + if (ret) { + dev_err(dev, "failed to get phy_addr port %u (%d)\n", + priv->port_id, ret); + goto out; + } + } + +out: + return ret; +} + +static int am65_cpsw_probe_cpsw(struct udevice *dev) +{ + struct am65_cpsw_priv *priv = dev_get_priv(dev); + struct eth_pdata *pdata = dev_get_platdata(dev); + struct am65_cpsw_common *cpsw_common; + ofnode ports_np, node; + int ret, i; + + priv->dev = dev; + + cpsw_common = calloc(1, sizeof(*priv->cpsw_common)); + if (!cpsw_common) + return -ENOMEM; + priv->cpsw_common = cpsw_common; + + cpsw_common->dev = dev; + cpsw_common->ss_base = dev_read_addr(dev); + if (cpsw_common->ss_base == FDT_ADDR_T_NONE) + return -EINVAL; + cpsw_common->mac_efuse = devfdt_get_addr_name(dev, "mac_efuse"); + /* no err check - optional */ + + ret = power_domain_get_by_index(dev, &cpsw_common->pwrdmn, 0); + if (ret) { + dev_err(dev, "failed to get pwrdmn: %d\n", ret); + return ret; + } + + ret = clk_get_by_name(dev, "fck", &cpsw_common->fclk); + if (ret) { + power_domain_free(&cpsw_common->pwrdmn); + dev_err(dev, "failed to get clock %d\n", ret); + return ret; + } + + cpsw_common->cpsw_base = cpsw_common->ss_base + AM65_CPSW_CPSW_NU_BASE; + cpsw_common->ale_base = cpsw_common->cpsw_base + + AM65_CPSW_CPSW_NU_ALE_BASE; + cpsw_common->mdio_base = cpsw_common->ss_base + AM65_CPSW_MDIO_BASE; + + cpsw_common->rflow_id_base = 0; + cpsw_common->rflow_id_base = + dev_read_u32_default(dev, "ti,rx-flow-id-base", + cpsw_common->rflow_id_base); + + ports_np = dev_read_subnode(dev, "ports"); + if (!ofnode_valid(ports_np)) { + ret = -ENOENT; + goto out; + } + + ofnode_for_each_subnode(node, ports_np) { + const char *node_name; + u32 port_id; + bool disabled; + + node_name = ofnode_get_name(node); + + disabled = !ofnode_is_available(node); + + ret = ofnode_read_u32(node, "reg", &port_id); + if (ret) { + dev_err(dev, "%s: failed to get port_id (%d)\n", + node_name, ret); + goto out; + } + + if (port_id >= AM65_CPSW_CPSWNU_MAX_PORTS) { + dev_err(dev, "%s: invalid port_id (%d)\n", + node_name, port_id); + ret = -EINVAL; + goto out; + } + cpsw_common->port_num++; + + if (!port_id) + continue; + + priv->port_id = port_id; + cpsw_common->ports[port_id].disabled = disabled; + if (disabled) + continue; + + ret = am65_cpsw_ofdata_parse_phy(dev, node); + if (ret) + goto out; + } + + for (i = 0; i < AM65_CPSW_CPSWNU_MAX_PORTS; i++) { + struct am65_cpsw_port *port = &cpsw_common->ports[i]; + + port->port_base = cpsw_common->cpsw_base + + AM65_CPSW_CPSW_NU_PORTS_OFFSET + + (i * AM65_CPSW_CPSW_NU_PORTS_OFFSET); + port->macsl_base = port->port_base + + AM65_CPSW_CPSW_NU_PORT_MACSL_OFFSET; + } + + node = dev_read_subnode(dev, "cpsw-phy-sel"); + if (!ofnode_valid(node)) { + dev_err(dev, "can't find cpsw-phy-sel\n"); + ret = -ENOENT; + goto out; + } + + cpsw_common->gmii_sel = ofnode_get_addr(node); + if (cpsw_common->gmii_sel == FDT_ADDR_T_NONE) { + dev_err(dev, "failed to get gmii_sel base\n"); + goto out; + } + + node = dev_read_subnode(dev, "mdio"); + if (!ofnode_valid(node)) { + dev_err(dev, "can't find mdio\n"); + ret = -ENOENT; + goto out; + } + + cpsw_common->bus_freq = + dev_read_u32_default(dev, "bus_freq", + AM65_CPSW_MDIO_BUS_FREQ_DEF); + + am65_cpsw_gmii_sel_k3(priv, pdata->phy_interface, priv->port_id); + + ret = am65_cpsw_mdio_init(dev); + if (ret) + goto out; + + ret = am65_cpsw_phy_init(dev); + if (ret) + goto out; + + dev_info(dev, "K3 CPSW: nuss_ver: 0x%08X cpsw_ver: 0x%08X ale_ver: 0x%08X Ports:%u rflow_id_base:%u mdio_freq:%u\n", + readl(cpsw_common->ss_base), + readl(cpsw_common->cpsw_base), + readl(cpsw_common->ale_base), + cpsw_common->port_num, + cpsw_common->rflow_id_base, + cpsw_common->bus_freq); + +out: + clk_free(&cpsw_common->fclk); + power_domain_free(&cpsw_common->pwrdmn); + return ret; +} + +static const struct udevice_id am65_cpsw_nuss_ids[] = { + { .compatible = "ti,am654-cpsw-nuss" }, + { } +}; + +U_BOOT_DRIVER(am65_cpsw_nuss_slave) = { + .name = "am65_cpsw_nuss_slave", + .id = UCLASS_ETH, + .of_match = am65_cpsw_nuss_ids, + .probe = am65_cpsw_probe_cpsw, + .ops = &am65_cpsw_ops, + .priv_auto_alloc_size = sizeof(struct am65_cpsw_priv), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/net/ti/cpsw_mdio.c b/drivers/net/ti/cpsw_mdio.c index 70f547e6d7..6e8f652011 100644 --- a/drivers/net/ti/cpsw_mdio.c +++ b/drivers/net/ti/cpsw_mdio.c @@ -125,7 +125,7 @@ u32 cpsw_mdio_get_alive(struct mii_dev *bus) return val & GENMASK(15, 0); } -struct mii_dev *cpsw_mdio_init(const char *name, u32 mdio_base, +struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base, u32 bus_freq, int fck_freq) { struct cpsw_mdio *cpsw_mdio; @@ -144,7 +144,7 @@ struct mii_dev *cpsw_mdio_init(const char *name, u32 mdio_base, return NULL; } - cpsw_mdio->regs = (struct cpsw_mdio_regs *)mdio_base; + cpsw_mdio->regs = (struct cpsw_mdio_regs *)(uintptr_t)mdio_base; if (!bus_freq || !fck_freq) cpsw_mdio->div = CPSW_MDIO_DIV_DEF; diff --git a/drivers/net/ti/cpsw_mdio.h b/drivers/net/ti/cpsw_mdio.h index 4a76d4e5c5..dbf4a2dcac 100644 --- a/drivers/net/ti/cpsw_mdio.h +++ b/drivers/net/ti/cpsw_mdio.h @@ -10,7 +10,7 @@ struct cpsw_mdio; -struct mii_dev *cpsw_mdio_init(const char *name, u32 mdio_base, +struct mii_dev *cpsw_mdio_init(const char *name, phys_addr_t mdio_base, u32 bus_freq, int fck_freq); void cpsw_mdio_free(struct mii_dev *bus); u32 cpsw_mdio_get_alive(struct mii_dev *bus); diff --git a/drivers/pinctrl/pinctrl_stm32.c b/drivers/pinctrl/pinctrl_stm32.c index 43dbdd9d6a..cdbe463cff 100644 --- a/drivers/pinctrl/pinctrl_stm32.c +++ b/drivers/pinctrl/pinctrl_stm32.c @@ -1,5 +1,6 @@ #include <common.h> #include <dm.h> +#include <dm/lists.h> #include <dm/pinctrl.h> #include <hwspinlock.h> #include <asm/arch/gpio.h> @@ -136,7 +137,7 @@ static struct udevice *stm32_pinctrl_get_gpio_dev(struct udevice *dev, */ *idx = stm32_offset_to_index(gpio_bank->gpio_dev, selector - pin_count); - if (*idx < 0) + if (IS_ERR_VALUE(*idx)) return NULL; return gpio_bank->gpio_dev; @@ -215,7 +216,7 @@ static int stm32_pinctrl_get_pin_muxing(struct udevice *dev, #endif -int stm32_pinctrl_probe(struct udevice *dev) +static int stm32_pinctrl_probe(struct udevice *dev) { struct stm32_pinctrl_priv *priv = dev_get_priv(dev); int ret; @@ -364,6 +365,35 @@ static int stm32_pinctrl_config(int offset) return 0; } +static int stm32_pinctrl_bind(struct udevice *dev) +{ + ofnode node; + const char *name; + int ret; + + dev_for_each_subnode(node, dev) { + debug("%s: bind %s\n", __func__, ofnode_get_name(node)); + + ofnode_get_property(node, "gpio-controller", &ret); + if (ret < 0) + continue; + /* Get the name of each gpio node */ + name = ofnode_get_name(node); + if (!name) + return -EINVAL; + + /* Bind each gpio node */ + ret = device_bind_driver_to_node(dev, "gpio_stm32", + name, node, NULL); + if (ret) + return ret; + + debug("%s: bind %s\n", __func__, name); + } + + return 0; +} + #if CONFIG_IS_ENABLED(PINCTRL_FULL) static int stm32_pinctrl_set_state(struct udevice *dev, struct udevice *config) { @@ -433,7 +463,7 @@ U_BOOT_DRIVER(pinctrl_stm32) = { .id = UCLASS_PINCTRL, .of_match = stm32_pinctrl_ids, .ops = &stm32_pinctrl_ops, - .bind = dm_scan_fdt_dev, + .bind = stm32_pinctrl_bind, .probe = stm32_pinctrl_probe, .priv_auto_alloc_size = sizeof(struct stm32_pinctrl_priv), }; diff --git a/drivers/power/pmic/stpmic1.c b/drivers/power/pmic/stpmic1.c index 65296c5fc3..c3381489dd 100644 --- a/drivers/power/pmic/stpmic1.c +++ b/drivers/power/pmic/stpmic1.c @@ -221,7 +221,7 @@ static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type) struct udevice *pmic_dev; int ret; - if (type != SYSRESET_POWER) + if (type != SYSRESET_POWER && type != SYSRESET_POWER_OFF) return -EPROTONOSUPPORT; ret = uclass_get_device_by_driver(UCLASS_PMIC, @@ -235,8 +235,13 @@ static int stpmic1_sysreset_request(struct udevice *dev, enum sysreset_t type) if (ret < 0) return ret; - ret = pmic_reg_write(pmic_dev, STPMIC1_MAIN_CR, - ret | STPMIC1_SWOFF | STPMIC1_RREQ_EN); + ret |= STPMIC1_SWOFF; + ret &= ~STPMIC1_RREQ_EN; + /* request Power Cycle */ + if (type == SYSRESET_POWER) + ret |= STPMIC1_RREQ_EN; + + ret = pmic_reg_write(pmic_dev, STPMIC1_MAIN_CR, ret); if (ret < 0) return ret; diff --git a/drivers/power/regulator/stm32-vrefbuf.c b/drivers/power/regulator/stm32-vrefbuf.c index 0ad6833ed0..645528e84e 100644 --- a/drivers/power/regulator/stm32-vrefbuf.c +++ b/drivers/power/regulator/stm32-vrefbuf.c @@ -30,7 +30,7 @@ struct stm32_vrefbuf { struct udevice *vdda_supply; }; -static const unsigned int stm32_vrefbuf_voltages[] = { +static const int stm32_vrefbuf_voltages[] = { /* Matches resp. VRS = 000b, 001b, 010b, 011b */ 2500000, 2048000, 1800000, 1500000, }; diff --git a/drivers/power/regulator/stpmic1.c b/drivers/power/regulator/stpmic1.c index 50ef2a21d1..1e3f96f3a0 100644 --- a/drivers/power/regulator/stpmic1.c +++ b/drivers/power/regulator/stpmic1.c @@ -422,6 +422,7 @@ static int stpmic1_ldo_set_mode(struct udevice *dev, int mode) case STPMIC1_LDO_MODE_SINK_SOURCE: ret &= ~STPMIC1_LDO12356_VOUT_MASK; ret |= STPMIC1_LDO3_DDR_SEL << STPMIC1_LDO12356_VOUT_SHIFT; + /* fallthrough */ case STPMIC1_LDO_MODE_NORMAL: ret &= ~STPMIC1_LDO3_MODE; break; diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c index 84e39d093b..a362cf98bf 100644 --- a/drivers/ram/stm32mp1/stm32mp1_ram.c +++ b/drivers/ram/stm32mp1/stm32mp1_ram.c @@ -26,7 +26,7 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) unsigned long ddr_clk; struct clk clk; int ret; - int idx; + unsigned int idx; for (idx = 0; idx < ARRAY_SIZE(clkname); idx++) { ret = clk_get_by_name(priv->dev, clkname[idx], &clk); @@ -59,7 +59,8 @@ int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev) { struct ddr_info *priv = dev_get_priv(dev); - int ret, idx; + int ret; + unsigned int idx; struct clk axidcg; struct stm32mp1_ddr_config config; diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c index cca8b707ac..3ab536a52a 100644 --- a/drivers/serial/serial_stm32.c +++ b/drivers/serial/serial_stm32.c @@ -195,9 +195,9 @@ static int stm32_serial_probe(struct udevice *dev) } plat->clock_rate = clk_get_rate(&clk); - if (plat->clock_rate < 0) { + if (!plat->clock_rate) { clk_disable(&clk); - return plat->clock_rate; + return -EINVAL; }; _stm32_serial_init(plat->base, plat->uart_info); diff --git a/drivers/spi/stm32_qspi.c b/drivers/spi/stm32_qspi.c index bb1067ff4a..8d612f22d6 100644 --- a/drivers/spi/stm32_qspi.c +++ b/drivers/spi/stm32_qspi.c @@ -361,9 +361,9 @@ static int stm32_qspi_probe(struct udevice *bus) } priv->clock_rate = clk_get_rate(&clk); - if (priv->clock_rate < 0) { + if (!priv->clock_rate) { clk_disable(&clk); - return priv->clock_rate; + return -EINVAL; } ret = reset_get_by_index(bus, 0, &reset_ctl); @@ -395,14 +395,15 @@ static int stm32_qspi_claim_bus(struct udevice *dev) { struct stm32_qspi_priv *priv = dev_get_priv(dev->parent); struct dm_spi_slave_platdata *slave_plat = dev_get_parent_platdata(dev); + int slave_cs = slave_plat->cs; - if (slave_plat->cs >= STM32_QSPI_MAX_CHIP) + if (slave_cs >= STM32_QSPI_MAX_CHIP) return -ENODEV; - if (priv->cs_used != slave_plat->cs) { - struct stm32_qspi_flash *flash = &priv->flash[slave_plat->cs]; + if (priv->cs_used != slave_cs) { + struct stm32_qspi_flash *flash = &priv->flash[slave_cs]; - priv->cs_used = slave_plat->cs; + priv->cs_used = slave_cs; if (flash->initialized) { /* Set the configuration: speed + cs */ @@ -444,11 +445,12 @@ static int stm32_qspi_set_speed(struct udevice *bus, uint speed) int ret; if (speed > 0) { - prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1; - if (prescaler > 255) - prescaler = 255; - else if (prescaler < 0) - prescaler = 0; + prescaler = 0; + if (qspi_clk) { + prescaler = DIV_ROUND_UP(qspi_clk, speed) - 1; + if (prescaler > 255) + prescaler = 255; + } } csht = DIV_ROUND_UP((5 * qspi_clk) / (prescaler + 1), 100000000); diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c index 34b217584d..75b6006b45 100644 --- a/drivers/spi/stm32_spi.c +++ b/drivers/spi/stm32_spi.c @@ -99,8 +99,8 @@ struct stm32_spi_priv { unsigned int cur_bpw; unsigned int cur_hz; unsigned int cur_xferlen; /* current transfer length in bytes */ - int tx_len; /* number of data to be written in bytes */ - int rx_len; /* number of data to be read in bytes */ + unsigned int tx_len; /* number of data to be written in bytes */ + unsigned int rx_len; /* number of data to be read in bytes */ const void *tx_buf; /* data to be written, or NULL */ void *rx_buf; /* data to be read, or NULL */ u32 cur_mode; @@ -322,7 +322,8 @@ static int stm32_spi_set_fthlv(struct udevice *dev, u32 xfer_len) static int stm32_spi_set_speed(struct udevice *bus, uint hz) { struct stm32_spi_priv *priv = dev_get_priv(bus); - u32 div, mbrdiv; + u32 mbrdiv; + long div; debug("%s: hz=%d\n", __func__, hz); @@ -341,7 +342,7 @@ static int stm32_spi_set_speed(struct udevice *bus, uint hz) else mbrdiv = fls(div) - 1; - if ((mbrdiv - 1) < 0) + if (!mbrdiv) return -EINVAL; clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_MBR, @@ -481,7 +482,7 @@ static int stm32_spi_probe(struct udevice *dev) struct stm32_spi_priv *priv = dev_get_priv(dev); unsigned long clk_rate; int ret; - int i; + unsigned int i; priv->base = dev_remap_addr(dev); if (!priv->base) diff --git a/drivers/sysreset/sysreset_syscon.c b/drivers/sysreset/sysreset_syscon.c index 1028160247..d0e586f66f 100644 --- a/drivers/sysreset/sysreset_syscon.c +++ b/drivers/sysreset/sysreset_syscon.c @@ -23,8 +23,9 @@ struct syscon_reboot_priv { static int syscon_reboot_request(struct udevice *dev, enum sysreset_t type) { struct syscon_reboot_priv *priv = dev_get_priv(dev); + ulong driver_data = dev_get_driver_data(dev); - if (type == SYSRESET_POWER) + if (type != driver_data) return -EPROTONOSUPPORT; regmap_write(priv->regmap, priv->offset, priv->mask); @@ -53,7 +54,8 @@ int syscon_reboot_probe(struct udevice *dev) } static const struct udevice_id syscon_reboot_ids[] = { - { .compatible = "syscon-reboot" }, + { .compatible = "syscon-reboot", .data = SYSRESET_COLD }, + { .compatible = "syscon-poweroff", .data = SYSRESET_POWER_OFF }, { /* sentinel */ } }; |