diff options
| author | Tom Rini <[email protected]> | 2025-11-24 09:34:29 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2025-11-24 09:34:29 -0600 |
| commit | 4a4871e3dc38f3f771d2713b805e79e6191b4297 (patch) | |
| tree | f3cbb63c259f8cce92e87bf1a30b69c02b07c2dc /drivers | |
| parent | 6e7d2399c8139f8e2d037e446236b8d8bdbca604 (diff) | |
| parent | c5e6d2ab7eba68cbfb600cdc131c0c375ced2ec9 (diff) | |
Merge tag 'v2026.01-rc3' into next
Prepare v2026.01-rc3
Diffstat (limited to 'drivers')
47 files changed, 1771 insertions, 3680 deletions
diff --git a/drivers/adc/stm32-adc-core.c b/drivers/adc/stm32-adc-core.c index af340b8b273..3446e34fa46 100644 --- a/drivers/adc/stm32-adc-core.c +++ b/drivers/adc/stm32-adc-core.c @@ -200,6 +200,7 @@ err_aclk_disable: static const struct udevice_id stm32_adc_core_ids[] = { { .compatible = "st,stm32h7-adc-core" }, { .compatible = "st,stm32mp1-adc-core" }, + { .compatible = "st,stm32mp13-adc-core" }, {} }; diff --git a/drivers/adc/stm32-adc.c b/drivers/adc/stm32-adc.c index d50f00f1233..b11f771b71c 100644 --- a/drivers/adc/stm32-adc.c +++ b/drivers/adc/stm32-adc.c @@ -49,29 +49,68 @@ /* STM32H7_ADC_SQR1 - bit fields */ #define STM32H7_SQ1_SHIFT 6 +/* STM32H7_ADC_DIFSEL - bit fields */ +#define STM32H7_DIFSEL_SHIFT 0 +#define STM32H7_DIFSEL_MASK GENMASK(19, 0) + /* BOOST bit must be set on STM32H7 when ADC clock is above 20MHz */ #define STM32H7_BOOST_CLKRATE 20000000UL +/* STM32MP13 - Registers for each ADC instance */ +#define STM32MP13_ADC_DIFSEL 0xB0 + +/* STM32MP13_ADC_CFGR specific bit fields */ +#define STM32MP13_DMAEN BIT(0) +#define STM32MP13_DMACFG BIT(1) + +/* STM32MP13_ADC_DIFSEL - bit fields */ +#define STM32MP13_DIFSEL_SHIFT 0 +#define STM32MP13_DIFSEL_MASK GENMASK(18, 0) + #define STM32_ADC_CH_MAX 20 /* max number of channels */ #define STM32_ADC_TIMEOUT_US 100000 +struct stm32_adc { + void __iomem *regs; + int active_channel; + const struct stm32_adc_cfg *cfg; +}; + +struct stm32_adc_regs { + int reg; + int mask; + int shift; +}; + +struct stm32_adc_regspec { + const struct stm32_adc_regs difsel; +}; + struct stm32_adc_cfg { + const struct stm32_adc_regspec *regs; unsigned int max_channels; unsigned int num_bits; bool has_vregready; + bool has_boostmode; + bool has_linearcal; + bool has_presel; }; -struct stm32_adc { - void __iomem *regs; - int active_channel; - const struct stm32_adc_cfg *cfg; +static const struct stm32_adc_regspec stm32h7_adc_regspec = { + .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK }, +}; + +static const struct stm32_adc_regspec stm32mp13_adc_regspec = { + .difsel = { STM32MP13_ADC_DIFSEL, STM32MP13_DIFSEL_MASK }, }; static void stm32_adc_enter_pwr_down(struct udevice *dev) { struct stm32_adc *adc = dev_get_priv(dev); - clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); + if (adc->cfg->has_boostmode) + clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); + /* Setting DEEPPWD disables ADC vreg and clears ADVREGEN */ setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); } @@ -90,8 +129,7 @@ static int stm32_adc_exit_pwr_down(struct udevice *dev) /* Exit deep power down, then enable ADC voltage regulator */ clrbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_DEEPPWD); setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADVREGEN); - - if (common->rate > STM32H7_BOOST_CLKRATE) + if (adc->cfg->has_boostmode && common->rate > STM32H7_BOOST_CLKRATE) setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_BOOST); /* Wait for startup time */ @@ -134,7 +172,7 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel) return ret; /* Only use single ended channels */ - writel(0, adc->regs + STM32H7_ADC_DIFSEL); + clrbits_le32(adc->regs + adc->cfg->regs->difsel.reg, adc->cfg->regs->difsel.mask); /* Enable ADC, Poll for ADRDY to be set (after adc startup time) */ setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADEN); @@ -147,7 +185,8 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel) } /* Preselect channels */ - writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL); + if (adc->cfg->has_presel) + writel(uc_pdata->channel_mask, adc->regs + STM32H7_ADC_PCSEL); /* Set sampling time to max value by default */ writel(0xffffffff, adc->regs + STM32H7_ADC_SMPR1); @@ -156,9 +195,11 @@ static int stm32_adc_start_channel(struct udevice *dev, int channel) /* Program regular sequence: chan in SQ1 & len = 0 for one channel */ writel(channel << STM32H7_SQ1_SHIFT, adc->regs + STM32H7_ADC_SQR1); - /* Trigger detection disabled (conversion can be launched in SW) */ - clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN | - STM32H7_DMNGT); + /* + * Trigger detection disabled (conversion can be launched in SW) + * STM32H7_DMNGT is equivalent to STM32MP13_DMAEN & STM32MP13_DMACFG + */ + clrbits_le32(adc->regs + STM32H7_ADC_CFGR, STM32H7_EXTEN | STM32H7_DMNGT); adc->active_channel = channel; return 0; @@ -206,7 +247,7 @@ static int stm32_adc_selfcalib(struct udevice *dev) { struct stm32_adc *adc = dev_get_priv(dev); int ret; - u32 val; + u32 val, mask; /* * Select calibration mode: @@ -231,7 +272,10 @@ static int stm32_adc_selfcalib(struct udevice *dev) * - Linearity calibration (needs to be done only once for single/diff) * will run simultaneously with offset calibration. */ - setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN); + mask = STM32H7_ADCALDIF; + if (adc->cfg->has_linearcal) + mask |= STM32H7_ADCALLIN; + setbits_le32(adc->regs + STM32H7_ADC_CR, mask); /* Start calibration, then wait for completion */ setbits_le32(adc->regs + STM32H7_ADC_CR, STM32H7_ADCAL); @@ -394,14 +438,28 @@ static const struct adc_ops stm32_adc_ops = { }; static const struct stm32_adc_cfg stm32h7_adc_cfg = { + .regs = &stm32h7_adc_regspec, .num_bits = 16, .max_channels = STM32_ADC_CH_MAX, + .has_boostmode = true, + .has_linearcal = true, + .has_presel = true, }; static const struct stm32_adc_cfg stm32mp1_adc_cfg = { + .regs = &stm32h7_adc_regspec, .num_bits = 16, .max_channels = STM32_ADC_CH_MAX, .has_vregready = true, + .has_boostmode = true, + .has_linearcal = true, + .has_presel = true, +}; + +static const struct stm32_adc_cfg stm32mp13_adc_cfg = { + .regs = &stm32mp13_adc_regspec, + .num_bits = 12, + .max_channels = STM32_ADC_CH_MAX - 1, }; static const struct udevice_id stm32_adc_ids[] = { @@ -409,6 +467,8 @@ static const struct udevice_id stm32_adc_ids[] = { .data = (ulong)&stm32h7_adc_cfg }, { .compatible = "st,stm32mp1-adc", .data = (ulong)&stm32mp1_adc_cfg }, + { .compatible = "st,stm32mp13-adc", + .data = (ulong)&stm32mp13_adc_cfg }, {} }; diff --git a/drivers/clk/clk_scmi.c b/drivers/clk/clk_scmi.c index a7d89f32cd7..683ac822a01 100644 --- a/drivers/clk/clk_scmi.c +++ b/drivers/clk/clk_scmi.c @@ -8,6 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <dm/device_compat.h> +#include <dm/device-internal.h> #include <scmi_agent.h> #include <scmi_agent-uclass.h> #include <scmi_protocols.h> @@ -16,7 +17,9 @@ struct clk_scmi { struct clk clk; + char name[SCMI_CLOCK_NAME_LENGTH_MAX]; u32 ctrl_flags; + bool attrs_resolved; }; struct scmi_clock_priv { @@ -84,7 +87,7 @@ static int scmi_clk_get_num_clock(struct udevice *dev, size_t *num_clocks) return 0; } -static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, +static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char *name, u32 *attr) { struct scmi_clock_priv *priv = dev_get_priv(dev); @@ -108,7 +111,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, if (ret) return ret; - *name = strdup(out.clock_name); + strncpy(name, out.clock_name, SCMI_CLOCK_NAME_LENGTH_MAX); *attr = out.attributes; } else { struct scmi_clk_attribute_out out; @@ -125,7 +128,7 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, if (ret) return ret; - *name = strdup(out.clock_name); + strncpy(name, out.clock_name, SCMI_CLOCK_NAME_LENGTH_MAX); *attr = out.attributes; } @@ -134,39 +137,93 @@ static int scmi_clk_get_attibute(struct udevice *dev, int clkid, char **name, static int scmi_clk_gate(struct clk *clk, int enable) { - struct scmi_clk_state_in in = { + struct scmi_clock_priv *priv = dev_get_parent_priv(clk->dev); + struct scmi_clk_state_in_v1 in_v1 = { + .clock_id = clk_get_id(clk), + .attributes = enable, + }; + /* Valid only from SCMI clock v2.1 */ + struct scmi_clk_state_in_v2 in_v2 = { .clock_id = clk_get_id(clk), .attributes = enable, }; struct scmi_clk_state_out out; - struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, - SCMI_CLOCK_CONFIG_SET, - in, out); + struct scmi_msg msg_v1 = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, + SCMI_CLOCK_CONFIG_SET, + in_v1, out); + struct scmi_msg msg_v2 = SCMI_MSG_IN(SCMI_PROTOCOL_ID_CLOCK, + SCMI_CLOCK_CONFIG_SET, + in_v2, out); int ret; - ret = devm_scmi_process_msg(clk->dev, &msg); + ret = devm_scmi_process_msg(clk->dev, + (priv->version < CLOCK_PROTOCOL_VERSION_2_1) ? + &msg_v1 : &msg_v2); if (ret) return ret; return scmi_to_linux_errno(out.status); } -static int scmi_clk_enable(struct clk *clk) +static int scmi_clk_get_ctrl_flags(struct clk *clk, u32 *ctrl_flags) { struct clk_scmi *clkscmi; + struct udevice *dev; + u32 attributes; struct clk *c; int ret; - if (!CONFIG_IS_ENABLED(CLK_CCF)) - return scmi_clk_gate(clk, 1); - ret = clk_get_by_id(clk->id, &c); if (ret) return ret; + dev = c->dev->parent; + clkscmi = container_of(c, struct clk_scmi, clk); - if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL) + if (!clkscmi->attrs_resolved) { + char name[SCMI_CLOCK_NAME_LENGTH_MAX]; + ret = scmi_clk_get_attibute(dev, clk->id & CLK_ID_MSK, + name, &attributes); + if (ret) + return ret; + + strncpy(clkscmi->name, name, SCMI_CLOCK_NAME_LENGTH_MAX); + if (CLK_HAS_RESTRICTIONS(attributes)) { + u32 perm; + + ret = scmi_clk_get_permissions(dev, clk->id & CLK_ID_MSK, &perm); + if (ret < 0) + clkscmi->ctrl_flags = 0; + else + clkscmi->ctrl_flags = perm; + } else { + clkscmi->ctrl_flags = SUPPORT_CLK_STAT_CONTROL | + SUPPORT_CLK_PARENT_CONTROL | + SUPPORT_CLK_RATE_CONTROL; + } + + clkscmi->attrs_resolved = true; + } + + *ctrl_flags = clkscmi->ctrl_flags; + + return 0; +} + +static int scmi_clk_enable(struct clk *clk) +{ + u32 ctrl_flags; + int ret; + + if (!CONFIG_IS_ENABLED(CLK_CCF)) + return scmi_clk_gate(clk, 1); + + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); + if (ret) + return ret; + + if (ctrl_flags & SUPPORT_CLK_STAT_CONTROL) return scmi_clk_gate(clk, 1); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ @@ -176,20 +233,17 @@ static int scmi_clk_enable(struct clk *clk) static int scmi_clk_disable(struct clk *clk) { - struct clk_scmi *clkscmi; - struct clk *c; + u32 ctrl_flags; int ret; if (!CONFIG_IS_ENABLED(CLK_CCF)) return scmi_clk_gate(clk, 0); - ret = clk_get_by_id(clk->id, &c); + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); if (ret) return ret; - clkscmi = container_of(c, struct clk_scmi, clk); - - if (clkscmi->ctrl_flags & SUPPORT_CLK_STAT_CONTROL) + if (ctrl_flags & SUPPORT_CLK_STAT_CONTROL) return scmi_clk_gate(clk, 0); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ @@ -247,20 +301,17 @@ static ulong __scmi_clk_set_rate(struct clk *clk, ulong rate) static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) { - struct clk_scmi *clkscmi; - struct clk *c; + u32 ctrl_flags; int ret; if (!CONFIG_IS_ENABLED(CLK_CCF)) return __scmi_clk_set_rate(clk, rate); - ret = clk_get_by_id(clk->id, &c); + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); if (ret) return ret; - clkscmi = container_of(c, struct clk_scmi, clk); - - if (clkscmi->ctrl_flags & SUPPORT_CLK_RATE_CONTROL) + if (ctrl_flags & SUPPORT_CLK_RATE_CONTROL) return __scmi_clk_set_rate(clk, rate); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ @@ -271,7 +322,7 @@ static ulong scmi_clk_set_rate(struct clk *clk, ulong rate) static int scmi_clk_probe(struct udevice *dev) { - struct clk_scmi *clk_scmi; + struct clk_scmi *clk_scmi_bulk, *clk_scmi; struct scmi_clock_priv *priv = dev_get_priv(dev); size_t num_clocks, i; int ret; @@ -300,39 +351,23 @@ static int scmi_clk_probe(struct udevice *dev) return ret; } - for (i = 0; i < num_clocks; i++) { - char *clock_name; - u32 attributes; - - if (!scmi_clk_get_attibute(dev, i, &clock_name, &attributes)) { - clk_scmi = kzalloc(sizeof(*clk_scmi), GFP_KERNEL); - if (!clk_scmi || !clock_name) - ret = -ENOMEM; - else - ret = clk_register(&clk_scmi->clk, dev->driver->name, - clock_name, dev->name); + clk_scmi_bulk = kzalloc(num_clocks * sizeof(*clk_scmi), GFP_KERNEL); + if (!clk_scmi_bulk) + return -ENOMEM; - if (ret) { - free(clk_scmi); - free(clock_name); - return ret; - } + for (i = 0; i < num_clocks; i++) { + clk_scmi = clk_scmi_bulk + i; + char *clock_name = clk_scmi->name; - dev_clk_dm(dev, i, &clk_scmi->clk); + snprintf(clock_name, SCMI_CLOCK_NAME_LENGTH_MAX, "scmi-%zu", i); - if (CLK_HAS_RESTRICTIONS(attributes)) { - u32 perm; + ret = clk_register(&clk_scmi->clk, dev->driver->name, + clock_name, dev->name); + if (ret) + return ret; - ret = scmi_clk_get_permissions(dev, i, &perm); - if (ret < 0) - clk_scmi->ctrl_flags = 0; - else - clk_scmi->ctrl_flags = perm; - } else { - clk_scmi->ctrl_flags = SUPPORT_CLK_STAT_CONTROL | SUPPORT_CLK_PARENT_CONTROL | - SUPPORT_CLK_RATE_CONTROL; - } - } + dev_clk_dm(dev, i, &clk_scmi->clk); + dev_set_parent_priv(clk_scmi->clk.dev, priv); } return 0; @@ -359,20 +394,17 @@ static int __scmi_clk_set_parent(struct clk *clk, struct clk *parent) static int scmi_clk_set_parent(struct clk *clk, struct clk *parent) { - struct clk_scmi *clkscmi; - struct clk *c; + u32 ctrl_flags; int ret; if (!CONFIG_IS_ENABLED(CLK_CCF)) - return -ENOTSUPP; + return __scmi_clk_set_parent(clk, parent); - ret = clk_get_by_id(clk->id, &c); + ret = scmi_clk_get_ctrl_flags(clk, &ctrl_flags); if (ret) return ret; - clkscmi = container_of(c, struct clk_scmi, clk); - - if (clkscmi->ctrl_flags & SUPPORT_CLK_PARENT_CONTROL) + if (ctrl_flags & SUPPORT_CLK_PARENT_CONTROL) return __scmi_clk_set_parent(clk, parent); /* Following Linux drivers/clk/clk-scmi.c, directly return 0 if agent has no permission. */ diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c index 071d998a0a5..cf1cf8abfbe 100644 --- a/drivers/core/ofnode.c +++ b/drivers/core/ofnode.c @@ -1221,13 +1221,16 @@ int ofnode_decode_display_timing(ofnode parent, int index, int ret = 0; timings = ofnode_find_subnode(parent, "display-timings"); - if (!ofnode_valid(timings)) - return -EINVAL; - - i = 0; - ofnode_for_each_subnode(node, timings) { - if (i++ == index) - break; + if (ofnode_valid(timings)) { + i = 0; + ofnode_for_each_subnode(node, timings) { + if (i++ == index) + break; + } + } else { + if (index != 0) + return -EINVAL; + node = ofnode_find_subnode(parent, "panel-timing"); } if (!ofnode_valid(node)) diff --git a/drivers/firmware/scmi/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c index 74a87832dcb..5b242a039c2 100644 --- a/drivers/firmware/scmi/sandbox-scmi_agent.c +++ b/drivers/firmware/scmi/sandbox-scmi_agent.c @@ -828,7 +828,7 @@ static int sandbox_scmi_clock_rate_get(struct udevice *dev, static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg) { - struct scmi_clk_state_in *in = NULL; + struct scmi_clk_state_in_v1 *in = NULL; struct scmi_clk_state_out *out = NULL; struct sandbox_scmi_clk *clk_state = NULL; @@ -836,7 +836,7 @@ static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg) !msg->out_msg || msg->out_msg_sz < sizeof(*out)) return -EINVAL; - in = (struct scmi_clk_state_in *)msg->in_msg; + in = (struct scmi_clk_state_in_v1 *)msg->in_msg; out = (struct scmi_clk_state_out *)msg->out_msg; clk_state = get_scmi_clk_state(in->clock_id); diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c index 237871559f0..cd1c0801f72 100644 --- a/drivers/firmware/scmi/smt.c +++ b/drivers/firmware/scmi/smt.c @@ -61,20 +61,6 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt) if (device_is_compatible(dev, "arm,scmi") && ofnode_has_property(dev_ofnode(dev), "mboxes")) scmi_smt_enable_intr(smt, true); -#ifdef CONFIG_ARM - if (dcache_status()) { - u32 align_size; - - if (IS_ENABLED(CONFIG_ARM64)) - align_size = PAGE_SIZE; - else - align_size = MMU_SECTION_SIZE; - - mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, align_size), - ALIGN(smt->size, align_size), DCACHE_OFF); - } -#endif - return 0; } diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a47c127d98c..142db9e47b8 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -356,6 +356,7 @@ config NPCM_SGPIO config OMAP_GPIO bool "TI OMAP GPIO driver" depends on ARCH_OMAP2PLUS + select TI_SYSC if OF_CONTROL default y help Support GPIO controllers on the TI OMAP3/4/5 and related (such as diff --git a/drivers/i2c/muxes/i2c-mux-uclass.c b/drivers/i2c/muxes/i2c-mux-uclass.c index 012881de05b..7f4eb914af2 100644 --- a/drivers/i2c/muxes/i2c-mux-uclass.c +++ b/drivers/i2c/muxes/i2c-mux-uclass.c @@ -130,7 +130,7 @@ static int i2c_mux_post_probe(struct udevice *mux) return 0; } -int i2c_mux_select(struct udevice *dev) +static int i2c_mux_select(struct udevice *dev) { struct i2c_mux_bus *plat = dev_get_parent_plat(dev); struct udevice *mux = dev->parent; @@ -142,7 +142,7 @@ int i2c_mux_select(struct udevice *dev) return ops->select(mux, dev, plat->channel); } -int i2c_mux_deselect(struct udevice *dev) +static int i2c_mux_deselect(struct udevice *dev) { struct i2c_mux_bus *plat = dev_get_parent_plat(dev); struct udevice *mux = dev->parent; diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index 754b99bf3eb..c76c10e1ef9 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -11,7 +11,6 @@ config SYS_NAND_SELF_INIT config SPL_SYS_NAND_SELF_INIT bool - depends on !SPL_NAND_SIMPLE help This option, if enabled, provides more flexible and linux-like NAND initialization process, in SPL. @@ -454,7 +453,6 @@ config NAND_SANDBOX select SYS_NAND_SELF_INIT select SPL_SYS_NAND_SELF_INIT select SPL_NAND_INIT - select SYS_NAND_SOFT_ECC select BCH select NAND_ECC_BCH imply CMD_NAND @@ -671,7 +669,6 @@ config SYS_NAND_PAGE_SIZE MVEBU_SPL_BOOT_DEVICE_NAND || \ (NAND_ATMEL && SPL_NAND_SUPPORT) || \ SPL_GENERATE_ATMEL_PMECC_HEADER || NAND_SANDBOX || NAND_CADENCE - depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC && !NAND_MT7621 help Number of data bytes in one page for the NAND chip on the board, not including the OOB area. @@ -681,7 +678,6 @@ config SYS_NAND_OOBSIZE depends on ARCH_SUNXI || NAND_OMAP_GPMC || \ SPL_NAND_SIMPLE || (NAND_MXC && SPL_NAND_SUPPORT) || \ (NAND_ATMEL && SPL_NAND_SUPPORT) || SPL_GENERATE_ATMEL_PMECC_HEADER - depends on !NAND_MXS && !NAND_DENALI_DT && !NAND_LPC32XX_MLC help Number of bytes in the Out-Of-Band area for the NAND chip on the board. diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile index 152aa1a3783..a7a0b2cb4b9 100644 --- a/drivers/mtd/nand/spi/Makefile +++ b/drivers/mtd/nand/spi/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 spinand-objs := core.o otp.o -spinand-objs += alliancememory.o ato.o esmt.o foresee.o gigadevice.o macronix.o +spinand-objs += alliancememory.o ato.o esmt.o fmsh.o foresee.o gigadevice.o macronix.o spinand-objs += micron.o paragon.o skyhigh.o toshiba.o winbond.o xtx.o obj-$(CONFIG_MTD_SPI_NAND) += spinand.o diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 0c435059546..14af4264612 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -1227,6 +1227,7 @@ static const struct spinand_manufacturer *spinand_manufacturers[] = { &alliancememory_spinand_manufacturer, &ato_spinand_manufacturer, &esmt_c8_spinand_manufacturer, + &fmsh_spinand_manufacturer, &foresee_spinand_manufacturer, &gigadevice_spinand_manufacturer, ¯onix_spinand_manufacturer, diff --git a/drivers/mtd/nand/spi/fmsh.c b/drivers/mtd/nand/spi/fmsh.c new file mode 100644 index 00000000000..80837b7dd42 --- /dev/null +++ b/drivers/mtd/nand/spi/fmsh.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd. + * + * Author: Dingqiang Lin <[email protected]> + */ + +#ifndef __UBOOT__ +#include <linux/device.h> +#include <linux/kernel.h> +#endif +#include <linux/mtd/spinand.h> + +#define SPINAND_MFR_FMSH 0xA1 + +static SPINAND_OP_VARIANTS(read_cache_variants, + SPINAND_PAGE_READ_FROM_CACHE_1S_4S_4S_OP(0, 2, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_4S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_2S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_2S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_FAST_1S_1S_1S_OP(0, 1, NULL, 0, 0), + SPINAND_PAGE_READ_FROM_CACHE_1S_1S_1S_OP(0, 1, NULL, 0, 0)); + +static SPINAND_OP_VARIANTS(write_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(true, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(true, 0, NULL, 0)); + +static SPINAND_OP_VARIANTS(update_cache_variants, + SPINAND_PROG_LOAD_1S_1S_4S_OP(false, 0, NULL, 0), + SPINAND_PROG_LOAD_1S_1S_1S_OP(false, 0, NULL, 0)); + +static int fm25s01a_ooblayout_ecc(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + return -ERANGE; +} + +static int fm25s01a_ooblayout_free(struct mtd_info *mtd, int section, + struct mtd_oob_region *region) +{ + if (section) + return -ERANGE; + + region->offset = 2; + region->length = 62; + + return 0; +} + +static const struct mtd_ooblayout_ops fm25s01a_ooblayout = { + .ecc = fm25s01a_ooblayout_ecc, + .rfree = fm25s01a_ooblayout_free, +}; + +static const struct spinand_info fmsh_spinand_table[] = { + SPINAND_INFO("FM25S01A", + SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE4), + NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1), + NAND_ECCREQ(1, 512), + SPINAND_INFO_OP_VARIANTS(&read_cache_variants, + &write_cache_variants, + &update_cache_variants), + 0, + SPINAND_ECCINFO(&fm25s01a_ooblayout, NULL)), +}; + +static const struct spinand_manufacturer_ops fmsh_spinand_manuf_ops = { +}; + +const struct spinand_manufacturer fmsh_spinand_manufacturer = { + .id = SPINAND_MFR_FMSH, + .name = "Fudan Micro", + .chips = fmsh_spinand_table, + .nchips = ARRAY_SIZE(fmsh_spinand_table), + .ops = &fmsh_spinand_manuf_ops, +}; diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c index 0383175beb5..b6a07fa9063 100644 --- a/drivers/mtd/spi/spi-nor-ids.c +++ b/drivers/mtd/spi/spi-nor-ids.c @@ -591,6 +591,12 @@ const struct flash_info spi_nor_ids[] = { { INFO("w25m512jw", 0xef6119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("w25m512jv", 0xef7119, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("w25h02jv", 0xef9022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h512nw-am", 0xefa020, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h01nw-am", 0xefa021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25h02nw-am", 0xefa022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q01nw-iq", 0xef6021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q01nw-im", 0xef8021, 0, 64 * 1024, 2048, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { INFO("w25q02nw-im", 0xef8022, 0, 64 * 1024, 4096, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { INFO("w77q51nw", 0xef8a1a, 0, 64 * 1024, 1024, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES) }, #endif #ifdef CONFIG_SPI_FLASH_XMC diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index 22e119370c8..fb48feb4469 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -619,11 +619,11 @@ static int axiemac_start(struct udevice *dev) #endif rx_bd.cntrl = sizeof(rxframe); /* Flush the last BD so DMA core could see the updates */ - flush_cache((phys_addr_t)&rx_bd, sizeof(rx_bd)); + flush_cache((phys_addr_t)(uintptr_t)&rx_bd, sizeof(rx_bd)); /* It is necessary to flush rxframe because if you don't do it * then cache can contain uninitialized data */ - flush_cache((phys_addr_t)&rxframe, sizeof(rxframe)); + flush_cache((phys_addr_t)(uintptr_t)&rxframe, sizeof(rxframe)); /* Start the hardware */ temp = readl(&priv->dmarx->control); @@ -675,7 +675,7 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len) } /* Flush packet to main memory to be trasfered by DMA */ - flush_cache((phys_addr_t)ptr, len); + flush_cache((phys_addr_t)(uintptr_t)ptr, len); /* Setup Tx BD */ memset(&tx_bd, 0, sizeof(tx_bd)); @@ -691,7 +691,7 @@ static int axiemac_send(struct udevice *dev, void *ptr, int len) XAXIDMA_BD_CTRL_TXEOF_MASK; /* Flush the last BD so DMA core could see the updates */ - flush_cache((phys_addr_t)&tx_bd, sizeof(tx_bd)); + flush_cache((phys_addr_t)(uintptr_t)&tx_bd, sizeof(tx_bd)); if (readl(&priv->dmatx->status) & XAXIDMA_HALTED_MASK) { u32 temp; @@ -791,11 +791,11 @@ static int axiemac_free_pkt(struct udevice *dev, uchar *packet, int length) rx_bd.cntrl = sizeof(rxframe); /* Write bd to HW */ - flush_cache((phys_addr_t)&rx_bd, sizeof(rx_bd)); + flush_cache((phys_addr_t)(uintptr_t)&rx_bd, sizeof(rx_bd)); /* It is necessary to flush rxframe because if you don't do it * then cache will contain previous packet */ - flush_cache((phys_addr_t)&rxframe, sizeof(rxframe)); + flush_cache((phys_addr_t)(uintptr_t)&rxframe, sizeof(rxframe)); /* Rx BD is ready - start again */ axienet_dma_write(&rx_bd, &priv->dmarx->tail); @@ -831,10 +831,10 @@ static int axi_emac_probe(struct udevice *dev) struct axidma_priv *priv = dev_get_priv(dev); int ret; - priv->iobase = (struct axi_regs *)pdata->iobase; + priv->iobase = (struct axi_regs *)(uintptr_t)pdata->iobase; priv->dmatx = plat->dmatx; /* RX channel offset is 0x30 */ - priv->dmarx = (struct axidma_reg *)((phys_addr_t)priv->dmatx + 0x30); + priv->dmarx = (struct axidma_reg *)((uintptr_t)priv->dmatx + 0x30); priv->mactype = plat->mactype; if (priv->mactype == EMAC_1G) { diff --git a/drivers/pinctrl/renesas/pfc-r8a779g0.c b/drivers/pinctrl/renesas/pfc-r8a779g0.c index ad113cd3e5d..c63adedd297 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779g0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779g0.c @@ -354,7 +354,7 @@ #define IP1SR2_3_0 FM(TPU0TO0_A) FM(CANFD6_RX) F_(0, 0) FM(TCLK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_15_12 FM(CANFD0_RX) FM(STPWT_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_15_12 FM(CANFD0_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2_A) F_(0, 0) FM(TCLK3_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3_A) FM(PWM1_B) FM(TCLK4_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -473,55 +473,55 @@ #define IP0SR6_7_4 FM(AVB1_MAGIC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR6_11_8 FM(AVB1_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR6_15_12 FM(AVB1_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_19_16 FM(AVB1_LINK) FM(AVB1_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_23_20 FM(AVB1_AVTP_MATCH) FM(AVB1_MII_RX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_27_24 FM(AVB1_TXC) FM(AVB1_MII_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR6_31_28 FM(AVB1_TX_CTL) FM(AVB1_MII_TX_EN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_19_16 FM(AVB1_LINK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_23_20 FM(AVB1_AVTP_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_27_24 FM(AVB1_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR6_31_28 FM(AVB1_TX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR6 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP1SR6_3_0 FM(AVB1_RXC) FM(AVB1_MII_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_7_4 FM(AVB1_RX_CTL) FM(AVB1_MII_RX_DV) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_11_8 FM(AVB1_AVTP_PPS) FM(AVB1_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_15_12 FM(AVB1_AVTP_CAPTURE) FM(AVB1_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_19_16 FM(AVB1_TD1) FM(AVB1_MII_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_23_20 FM(AVB1_TD0) FM(AVB1_MII_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_27_24 FM(AVB1_RD1) FM(AVB1_MII_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR6_31_28 FM(AVB1_RD0) FM(AVB1_MII_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_3_0 FM(AVB1_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_7_4 FM(AVB1_RX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_11_8 FM(AVB1_AVTP_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_15_12 FM(AVB1_AVTP_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_19_16 FM(AVB1_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_23_20 FM(AVB1_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_27_24 FM(AVB1_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR6_31_28 FM(AVB1_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR6 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP2SR6_3_0 FM(AVB1_TD2) FM(AVB1_MII_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR6_7_4 FM(AVB1_RD2) FM(AVB1_MII_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR6_11_8 FM(AVB1_TD3) FM(AVB1_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR6_15_12 FM(AVB1_RD3) FM(AVB1_MII_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_3_0 FM(AVB1_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_7_4 FM(AVB1_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_11_8 FM(AVB1_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR6_15_12 FM(AVB1_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP2SR6_19_16 FM(AVB1_TXCREFCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* SR7 */ /* IP0SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP0SR7_3_0 FM(AVB0_AVTP_PPS) FM(AVB0_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) FM(AVB0_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) FM(CC5_OSCOUT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_15_12 FM(AVB0_TD3) FM(AVB0_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_19_16 FM(AVB0_LINK) FM(AVB0_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_3_0 FM(AVB0_AVTP_PPS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_15_12 FM(AVB0_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_19_16 FM(AVB0_LINK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_23_20 FM(AVB0_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_27_24 FM(AVB0_TD2) FM(AVB0_MII_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_31_28 FM(AVB0_TD1) FM(AVB0_MII_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_27_24 FM(AVB0_TD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_31_28 FM(AVB0_TD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP1SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP1SR7_3_0 FM(AVB0_RD3) FM(AVB0_MII_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_3_0 FM(AVB0_RD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_7_4 FM(AVB0_TXCREFCLK) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_11_8 FM(AVB0_MAGIC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR7_15_12 FM(AVB0_TD0) FM(AVB0_MII_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR7_19_16 FM(AVB0_RD2) FM(AVB0_MII_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_15_12 FM(AVB0_TD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_19_16 FM(AVB0_RD2) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_23_20 FM(AVB0_MDC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR7_27_24 FM(AVB0_MDIO) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR7_31_28 FM(AVB0_TXC) FM(AVB0_MII_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR7_31_28 FM(AVB0_TXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* IP2SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ -#define IP2SR7_3_0 FM(AVB0_TX_CTL) FM(AVB0_MII_TX_EN) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_7_4 FM(AVB0_RD1) FM(AVB0_MII_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_11_8 FM(AVB0_RD0) FM(AVB0_MII_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_15_12 FM(AVB0_RXC) FM(AVB0_MII_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP2SR7_19_16 FM(AVB0_RX_CTL) FM(AVB0_MII_RX_DV) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_3_0 FM(AVB0_TX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_7_4 FM(AVB0_RD1) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_11_8 FM(AVB0_RD0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_15_12 FM(AVB0_RXC) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP2SR7_19_16 FM(AVB0_RX_CTL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) /* SR8 */ /* IP0SR8 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ @@ -927,7 +927,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_B), PINMUX_IPSR_GPSR(IP1SR2_15_12, CANFD0_RX), - PINMUX_IPSR_GPSR(IP1SR2_15_12, STPWT_EXTFXR), PINMUX_IPSR_GPSR(IP1SR2_19_16, CANFD2_TX), PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2_A), @@ -1078,118 +1077,85 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP0SR6_15_12, AVB1_PHY_INT), PINMUX_IPSR_GPSR(IP0SR6_19_16, AVB1_LINK), - PINMUX_IPSR_GPSR(IP0SR6_19_16, AVB1_MII_TX_ER), PINMUX_IPSR_GPSR(IP0SR6_23_20, AVB1_AVTP_MATCH), - PINMUX_IPSR_GPSR(IP0SR6_23_20, AVB1_MII_RX_ER), PINMUX_IPSR_GPSR(IP0SR6_27_24, AVB1_TXC), - PINMUX_IPSR_GPSR(IP0SR6_27_24, AVB1_MII_TXC), PINMUX_IPSR_GPSR(IP0SR6_31_28, AVB1_TX_CTL), - PINMUX_IPSR_GPSR(IP0SR6_31_28, AVB1_MII_TX_EN), /* IP1SR6 */ PINMUX_IPSR_GPSR(IP1SR6_3_0, AVB1_RXC), - PINMUX_IPSR_GPSR(IP1SR6_3_0, AVB1_MII_RXC), PINMUX_IPSR_GPSR(IP1SR6_7_4, AVB1_RX_CTL), - PINMUX_IPSR_GPSR(IP1SR6_7_4, AVB1_MII_RX_DV), PINMUX_IPSR_GPSR(IP1SR6_11_8, AVB1_AVTP_PPS), - PINMUX_IPSR_GPSR(IP1SR6_11_8, AVB1_MII_COL), PINMUX_IPSR_GPSR(IP1SR6_15_12, AVB1_AVTP_CAPTURE), - PINMUX_IPSR_GPSR(IP1SR6_15_12, AVB1_MII_CRS), PINMUX_IPSR_GPSR(IP1SR6_19_16, AVB1_TD1), - PINMUX_IPSR_GPSR(IP1SR6_19_16, AVB1_MII_TD1), PINMUX_IPSR_GPSR(IP1SR6_23_20, AVB1_TD0), - PINMUX_IPSR_GPSR(IP1SR6_23_20, AVB1_MII_TD0), PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_RD1), - PINMUX_IPSR_GPSR(IP1SR6_27_24, AVB1_MII_RD1), PINMUX_IPSR_GPSR(IP1SR6_31_28, AVB1_RD0), - PINMUX_IPSR_GPSR(IP1SR6_31_28, AVB1_MII_RD0), /* IP2SR6 */ PINMUX_IPSR_GPSR(IP2SR6_3_0, AVB1_TD2), - PINMUX_IPSR_GPSR(IP2SR6_3_0, AVB1_MII_TD2), PINMUX_IPSR_GPSR(IP2SR6_7_4, AVB1_RD2), - PINMUX_IPSR_GPSR(IP2SR6_7_4, AVB1_MII_RD2), PINMUX_IPSR_GPSR(IP2SR6_11_8, AVB1_TD3), - PINMUX_IPSR_GPSR(IP2SR6_11_8, AVB1_MII_TD3), PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_RD3), - PINMUX_IPSR_GPSR(IP2SR6_15_12, AVB1_MII_RD3), PINMUX_IPSR_GPSR(IP2SR6_19_16, AVB1_TXCREFCLK), /* IP0SR7 */ PINMUX_IPSR_GPSR(IP0SR7_3_0, AVB0_AVTP_PPS), - PINMUX_IPSR_GPSR(IP0SR7_3_0, AVB0_MII_COL), PINMUX_IPSR_GPSR(IP0SR7_7_4, AVB0_AVTP_CAPTURE), - PINMUX_IPSR_GPSR(IP0SR7_7_4, AVB0_MII_CRS), PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_AVTP_MATCH), - PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_MII_RX_ER), - PINMUX_IPSR_GPSR(IP0SR7_11_8, CC5_OSCOUT), PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_TD3), - PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_MII_TD3), PINMUX_IPSR_GPSR(IP0SR7_19_16, AVB0_LINK), - PINMUX_IPSR_GPSR(IP0SR7_19_16, AVB0_MII_TX_ER), PINMUX_IPSR_GPSR(IP0SR7_23_20, AVB0_PHY_INT), PINMUX_IPSR_GPSR(IP0SR7_27_24, AVB0_TD2), - PINMUX_IPSR_GPSR(IP0SR7_27_24, AVB0_MII_TD2), PINMUX_IPSR_GPSR(IP0SR7_31_28, AVB0_TD1), - PINMUX_IPSR_GPSR(IP0SR7_31_28, AVB0_MII_TD1), /* IP1SR7 */ PINMUX_IPSR_GPSR(IP1SR7_3_0, AVB0_RD3), - PINMUX_IPSR_GPSR(IP1SR7_3_0, AVB0_MII_RD3), PINMUX_IPSR_GPSR(IP1SR7_7_4, AVB0_TXCREFCLK), PINMUX_IPSR_GPSR(IP1SR7_11_8, AVB0_MAGIC), PINMUX_IPSR_GPSR(IP1SR7_15_12, AVB0_TD0), - PINMUX_IPSR_GPSR(IP1SR7_15_12, AVB0_MII_TD0), PINMUX_IPSR_GPSR(IP1SR7_19_16, AVB0_RD2), - PINMUX_IPSR_GPSR(IP1SR7_19_16, AVB0_MII_RD2), PINMUX_IPSR_GPSR(IP1SR7_23_20, AVB0_MDC), PINMUX_IPSR_GPSR(IP1SR7_27_24, AVB0_MDIO), PINMUX_IPSR_GPSR(IP1SR7_31_28, AVB0_TXC), - PINMUX_IPSR_GPSR(IP1SR7_31_28, AVB0_MII_TXC), /* IP2SR7 */ PINMUX_IPSR_GPSR(IP2SR7_3_0, AVB0_TX_CTL), - PINMUX_IPSR_GPSR(IP2SR7_3_0, AVB0_MII_TX_EN), PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_RD1), - PINMUX_IPSR_GPSR(IP2SR7_7_4, AVB0_MII_RD1), PINMUX_IPSR_GPSR(IP2SR7_11_8, AVB0_RD0), - PINMUX_IPSR_GPSR(IP2SR7_11_8, AVB0_MII_RD0), PINMUX_IPSR_GPSR(IP2SR7_15_12, AVB0_RXC), - PINMUX_IPSR_GPSR(IP2SR7_15_12, AVB0_MII_RXC), PINMUX_IPSR_GPSR(IP2SR7_19_16, AVB0_RX_CTL), - PINMUX_IPSR_GPSR(IP2SR7_19_16, AVB0_MII_RX_DV), /* IP0SR8 */ PINMUX_IPSR_MSEL(IP0SR8_3_0, SCL0, SEL_SCL0_0), diff --git a/drivers/pinctrl/renesas/pfc-r8a779h0.c b/drivers/pinctrl/renesas/pfc-r8a779h0.c index d6c2fbcf854..2c6c901f3a4 100644 --- a/drivers/pinctrl/renesas/pfc-r8a779h0.c +++ b/drivers/pinctrl/renesas/pfc-r8a779h0.c @@ -342,7 +342,7 @@ #define IP1SR2_3_0 FM(TPU0TO0_A) F_(0, 0) F_(0, 0) FM(TCLK1_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_7_4 FM(CAN_CLK) FM(FXR_TXENA_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_11_8 FM(CANFD0_TX) FM(FXR_TXENB_N_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP1SR2_15_12 FM(CANFD0_RX) FM(STPWT_EXTFXR) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP1SR2_15_12 FM(CANFD0_RX) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_19_16 FM(CANFD2_TX) FM(TPU0TO2_A) F_(0, 0) FM(TCLK3_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_23_20 FM(CANFD2_RX) FM(TPU0TO3_A) FM(PWM1_B) FM(TCLK4_C) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP1SR2_27_24 FM(CANFD3_TX) F_(0, 0) FM(PWM2_B) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -481,7 +481,7 @@ /* IP0SR7 */ /* 0 */ /* 1 */ /* 2 */ /* 3 4 5 6 7 8 9 A B C D E F */ #define IP0SR7_3_0 FM(AVB0_AVTP_PPS) FM(AVB0_MII_COL) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_7_4 FM(AVB0_AVTP_CAPTURE) FM(AVB0_MII_CRS) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) -#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) FM(CC5_OSCOUT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) +#define IP0SR7_11_8 FM(AVB0_AVTP_MATCH) FM(AVB0_MII_RX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_15_12 FM(AVB0_TD3) FM(AVB0_MII_TD3) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_19_16 FM(AVB0_LINK) FM(AVB0_MII_TX_ER) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) #define IP0SR7_23_20 FM(AVB0_PHY_INT) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) F_(0, 0) @@ -868,7 +868,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP1SR2_11_8, FXR_TXENB_N_B), PINMUX_IPSR_GPSR(IP1SR2_15_12, CANFD0_RX), - PINMUX_IPSR_GPSR(IP1SR2_15_12, STPWT_EXTFXR), PINMUX_IPSR_GPSR(IP1SR2_19_16, CANFD2_TX), PINMUX_IPSR_GPSR(IP1SR2_19_16, TPU0TO2_A), @@ -1126,7 +1125,6 @@ static const u16 pinmux_data[] = { PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_AVTP_MATCH), PINMUX_IPSR_GPSR(IP0SR7_11_8, AVB0_MII_RX_ER), - PINMUX_IPSR_GPSR(IP0SR7_11_8, CC5_OSCOUT), PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_TD3), PINMUX_IPSR_GPSR(IP0SR7_15_12, AVB0_MII_TD3), diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 05608399be1..b414d022f3f 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -584,7 +584,7 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose) struct udevice *bdev; struct blk_desc bd; struct blk_desc *bdesc; - char str[10], *name; + char str[10]; /* * detect the scsi driver to get information about its geometry (block @@ -600,10 +600,7 @@ static int do_scsi_scan_one(struct udevice *dev, int id, int lun, bool verbose) * block devices created */ snprintf(str, sizeof(str), "id%dlun%d", id, lun); - name = strdup(str); - if (!name) - return log_msg_ret("nam", -ENOMEM); - ret = blk_create_devicef(dev, "scsi_blk", name, UCLASS_SCSI, -1, + ret = blk_create_devicef(dev, "scsi_blk", str, UCLASS_SCSI, -1, bd.blksz, bd.lba, &bdev); if (ret) { debug("Can't create device\n"); diff --git a/drivers/spi/airoha_snfi_spi.c b/drivers/spi/airoha_snfi_spi.c index 3ea25b293d1..769ec956793 100644 --- a/drivers/spi/airoha_snfi_spi.c +++ b/drivers/spi/airoha_snfi_spi.c @@ -141,12 +141,15 @@ #define SPI_NFI_CUS_SEC_SIZE_EN BIT(16) #define REG_SPI_NFI_RD_CTL2 0x0510 +#define SPI_NFI_DATA_READ_CMD GENMASK(7, 0) + #define REG_SPI_NFI_RD_CTL3 0x0514 #define REG_SPI_NFI_PG_CTL1 0x0524 #define SPI_NFI_PG_LOAD_CMD GENMASK(15, 8) #define REG_SPI_NFI_PG_CTL2 0x0528 + #define REG_SPI_NFI_NOR_PROG_ADDR 0x052c #define REG_SPI_NFI_NOR_RD_ADDR 0x0534 @@ -173,7 +176,9 @@ #define SPI_NAND_OP_READ_FROM_CACHE_SINGLE 0x03 #define SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST 0x0b #define SPI_NAND_OP_READ_FROM_CACHE_DUAL 0x3b +#define SPI_NAND_OP_READ_FROM_CACHE_DUALIO 0xbb #define SPI_NAND_OP_READ_FROM_CACHE_QUAD 0x6b +#define SPI_NAND_OP_READ_FROM_CACHE_QUADIO 0xeb #define SPI_NAND_OP_WRITE_ENABLE 0x06 #define SPI_NAND_OP_WRITE_DISABLE 0x04 #define SPI_NAND_OP_PROGRAM_LOAD_SINGLE 0x02 @@ -186,6 +191,14 @@ #define SPI_NAND_OP_RESET 0xff #define SPI_NAND_OP_DIE_SELECT 0xc2 +/* SNAND FIFO commands */ +#define SNAND_FIFO_TX_BUSWIDTH_SINGLE 0x08 +#define SNAND_FIFO_TX_BUSWIDTH_DUAL 0x09 +#define SNAND_FIFO_TX_BUSWIDTH_QUAD 0x0a +#define SNAND_FIFO_RX_BUSWIDTH_SINGLE 0x0c +#define SNAND_FIFO_RX_BUSWIDTH_DUAL 0x0e +#define SNAND_FIFO_RX_BUSWIDTH_QUAD 0x0f + #define SPI_NAND_CACHE_SIZE (SZ_4K + SZ_256) #define SPI_MAX_TRANSFER_SIZE 511 @@ -205,12 +218,8 @@ struct airoha_snand_priv { struct regmap *regmap_nfi; struct clk *spi_clk; - struct { - size_t page_size; - size_t sec_size; - u8 sec_num; - u8 spare_size; - } nfi_cfg; + u8 *txrx_buf; + int dma; }; static int airoha_snand_set_fifo_op(struct airoha_snand_priv *priv, @@ -380,10 +389,26 @@ static int airoha_snand_set_mode(struct airoha_snand_priv *priv, return regmap_write(priv->regmap_ctrl, REG_SPI_CTRL_DUMMY, 0); } -static int airoha_snand_write_data(struct airoha_snand_priv *priv, u8 cmd, - const u8 *data, int len) +static int airoha_snand_write_data(struct airoha_snand_priv *priv, + const u8 *data, int len, int buswidth) { int i, data_len; + u8 cmd; + + switch (buswidth) { + case 0: + case 1: + cmd = SNAND_FIFO_TX_BUSWIDTH_SINGLE; + break; + case 2: + cmd = SNAND_FIFO_TX_BUSWIDTH_DUAL; + break; + case 4: + cmd = SNAND_FIFO_TX_BUSWIDTH_QUAD; + break; + default: + return -EINVAL; + } for (i = 0; i < len; i += data_len) { int err; @@ -402,16 +427,32 @@ static int airoha_snand_write_data(struct airoha_snand_priv *priv, u8 cmd, return 0; } -static int airoha_snand_read_data(struct airoha_snand_priv *priv, u8 *data, - int len) +static int airoha_snand_read_data(struct airoha_snand_priv *priv, + u8 *data, int len, int buswidth) { int i, data_len; + u8 cmd; + + switch (buswidth) { + case 0: + case 1: + cmd = SNAND_FIFO_RX_BUSWIDTH_SINGLE; + break; + case 2: + cmd = SNAND_FIFO_RX_BUSWIDTH_DUAL; + break; + case 4: + cmd = SNAND_FIFO_RX_BUSWIDTH_QUAD; + break; + default: + return -EINVAL; + } for (i = 0; i < len; i += data_len) { int err; data_len = min(len - i, SPI_MAX_TRANSFER_SIZE); - err = airoha_snand_set_fifo_op(priv, 0xc, data_len); + err = airoha_snand_set_fifo_op(priv, cmd, data_len); if (err) return err; @@ -439,131 +480,498 @@ static int airoha_snand_nfi_init(struct airoha_snand_priv *priv) SPI_NFI_ALL_IRQ_EN, SPI_NFI_AHB_DONE_EN); } -static int airoha_snand_nfi_config(struct airoha_snand_priv *priv) +static bool airoha_snand_is_page_ops(const struct spi_mem_op *op) { + if (op->addr.nbytes != 2) + return false; + + if (op->addr.buswidth != 1 && op->addr.buswidth != 2 && + op->addr.buswidth != 4) + return false; + + switch (op->data.dir) { + case SPI_MEM_DATA_IN: + if (op->dummy.nbytes * BITS_PER_BYTE / op->dummy.buswidth > 0xf) + return false; + + /* quad in / quad out */ + if (op->addr.buswidth == 4) + return op->data.buswidth == 4; + + if (op->addr.buswidth == 2) + return op->data.buswidth == 2; + + /* standard spi */ + return op->data.buswidth == 4 || op->data.buswidth == 2 || + op->data.buswidth == 1; + case SPI_MEM_DATA_OUT: + return !op->dummy.nbytes && op->addr.buswidth == 1 && + (op->data.buswidth == 4 || op->data.buswidth == 1); + default: + return false; + } +} + +static bool airoha_snand_supports_op(struct spi_slave *slave, + const struct spi_mem_op *op) +{ + if (!spi_mem_default_supports_op(slave, op)) + return false; + + if (op->cmd.buswidth != 1) + return false; + + if (airoha_snand_is_page_ops(op)) + return true; + + return (!op->addr.nbytes || op->addr.buswidth == 1) && + (!op->dummy.nbytes || op->dummy.buswidth == 1) && + (!op->data.nbytes || op->data.buswidth == 1); +} + +static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) +{ + struct spi_slave *slave = desc->slave; + struct udevice *bus = slave->dev->parent; + struct airoha_snand_priv *priv = dev_get_priv(bus); + + if (!priv->txrx_buf) + return -EINVAL; + + if (desc->info.offset + desc->info.length > U32_MAX) + return -EINVAL; + + /* continuous reading is not supported */ + if (desc->info.length > SPI_NAND_CACHE_SIZE) + return -E2BIG; + + if (!airoha_snand_supports_op(desc->slave, &desc->info.op_tmpl)) + return -EOPNOTSUPP; + + return 0; +} + +static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, void *buf) +{ + struct spi_slave *slave = desc->slave; + struct udevice *bus = slave->dev->parent; + struct airoha_snand_priv *priv = dev_get_priv(bus); + u8 *txrx_buf = priv->txrx_buf; + dma_addr_t dma_addr; + u32 val, rd_mode, opcode; + size_t bytes; int err; - u32 val; + if (!priv->dma) { + /* simplified version of spi_mem_no_dirmap_read() */ + struct spi_mem_op op = desc->info.op_tmpl; + + op.addr.val = desc->info.offset + offs; + op.data.buf.in = buf; + op.data.nbytes = len; + err = spi_mem_exec_op(desc->slave, &op); + if (err) + return err; + + return op.data.nbytes; + } + + /* minimum oob size is 64 */ + bytes = round_up(offs + len, 64); + + /* + * DUALIO and QUADIO opcodes are not supported by the spi controller, + * replace them with supported opcodes. + */ + opcode = desc->info.op_tmpl.cmd.opcode; + switch (opcode) { + case SPI_NAND_OP_READ_FROM_CACHE_SINGLE: + case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST: + rd_mode = 0; + break; + case SPI_NAND_OP_READ_FROM_CACHE_DUAL: + case SPI_NAND_OP_READ_FROM_CACHE_DUALIO: + opcode = SPI_NAND_OP_READ_FROM_CACHE_DUAL; + rd_mode = 1; + break; + case SPI_NAND_OP_READ_FROM_CACHE_QUAD: + case SPI_NAND_OP_READ_FROM_CACHE_QUADIO: + opcode = SPI_NAND_OP_READ_FROM_CACHE_QUAD; + rd_mode = 2; + break; + default: + /* unknown opcode */ + return -EOPNOTSUPP; + } + + err = airoha_snand_set_mode(priv, SPI_MODE_DMA); + if (err < 0) + return err; + + /* NFI reset */ err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); if (err) - return err; + goto error_dma_mode_off; - /* auto FDM */ - err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_AUTO_FDM_EN); + /* NFI configure: + * - No AutoFDM (custom sector size (SECCUS) register will be used) + * - No SoC's hardware ECC (flash internal ECC will be used) + * - Use burst mode (faster, but requires 16 byte alignment for addresses) + * - Setup for reading (SPI_NFI_READ_MODE) + * - Setup reading command: FIELD_PREP(SPI_NFI_OPMODE, 6) + * - Use DMA instead of PIO for data reading + */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_DMA_MODE | + SPI_NFI_READ_MODE | + SPI_NFI_DMA_BURST_EN | + SPI_NFI_HW_ECC_EN | + SPI_NFI_AUTO_FDM_EN | + SPI_NFI_OPMODE, + SPI_NFI_DMA_MODE | + SPI_NFI_READ_MODE | + SPI_NFI_DMA_BURST_EN | + FIELD_PREP(SPI_NFI_OPMODE, 6)); if (err) - return err; + goto error_dma_mode_off; - /* HW ECC */ - err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_HW_ECC_EN); + /* Set number of sector will be read */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_SEC_NUM, + FIELD_PREP(SPI_NFI_SEC_NUM, 1)); if (err) - return err; + goto error_dma_mode_off; - /* DMA Burst */ - err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_DMA_BURST_EN); + /* Set custom sector size */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE | + SPI_NFI_CUS_SEC_SIZE_EN, + FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) | + SPI_NFI_CUS_SEC_SIZE_EN); if (err) - return err; + goto error_dma_mode_off; - /* page format */ - switch (priv->nfi_cfg.spare_size) { - case 26: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x1); - break; - case 27: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x2); - break; - case 28: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x3); - break; - default: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x0); - break; - } + dma_addr = dma_map_single(txrx_buf, SPI_NAND_CACHE_SIZE, + DMA_FROM_DEVICE); + + /* set dma addr */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_STRADDR, + dma_addr); + if (err) + goto error_dma_unmap; + + /* + * Setup transfer length + * --------------------- + * The following rule MUST be met: + * transfer_length = + * = NFI_SNF_MISC_CTL2.read_data_byte_number = + * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size + */ + err = regmap_update_bits(priv->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, + SPI_NFI_READ_DATA_BYTE_NUM, + FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, bytes)); + if (err) + goto error_dma_unmap; + + /* set read command */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_RD_CTL2, + FIELD_PREP(SPI_NFI_DATA_READ_CMD, opcode)); + if (err) + goto error_dma_unmap; + + /* set read mode */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, + FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, rd_mode)); + if (err) + goto error_dma_unmap; + + /* set read addr: zero page offset + descriptor read offset */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_RD_CTL3, + desc->info.offset); + if (err) + goto error_dma_unmap; + + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CMD, 0x0); + if (err) + goto error_dma_unmap; + + /* trigger dma reading */ + err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_RD_TRIG); + if (err) + goto error_dma_unmap; - err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_PAGEFMT, - SPI_NFI_SPARE_SIZE, val); + err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_RD_TRIG); if (err) + goto error_dma_unmap; + + err = regmap_read_poll_timeout(priv->regmap_nfi, + REG_SPI_NFI_SNF_STA_CTL1, val, + (val & SPI_NFI_READ_FROM_CACHE_DONE), + 0, 1 * MSEC_PER_SEC); + if (err) + goto error_dma_unmap; + + /* + * SPI_NFI_READ_FROM_CACHE_DONE bit must be written at the end + * of dirmap_read operation even if it is already set. + */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1, + SPI_NFI_READ_FROM_CACHE_DONE, + SPI_NFI_READ_FROM_CACHE_DONE); + if (err) + goto error_dma_unmap; + + err = regmap_read_poll_timeout(priv->regmap_nfi, REG_SPI_NFI_INTR, + val, (val & SPI_NFI_AHB_DONE), 0, + 1 * MSEC_PER_SEC); + if (err) + goto error_dma_unmap; + + /* DMA read need delay for data ready from controller to DRAM */ + udelay(1); + + dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_FROM_DEVICE); + + err = airoha_snand_set_mode(priv, SPI_MODE_MANUAL); + if (err < 0) return err; - switch (priv->nfi_cfg.page_size) { - case 2048: - val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x1); + memcpy(buf, txrx_buf + offs, len); + + return len; + +error_dma_unmap: + dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_FROM_DEVICE); +error_dma_mode_off: + airoha_snand_set_mode(priv, SPI_MODE_MANUAL); + return err; +} + +static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, const void *buf) +{ + struct spi_slave *slave = desc->slave; + struct udevice *bus = slave->dev->parent; + struct airoha_snand_priv *priv = dev_get_priv(bus); + u8 *txrx_buf = priv->txrx_buf; + dma_addr_t dma_addr; + u32 wr_mode, val, opcode; + size_t bytes; + int err; + + if (!priv->dma) { + /* simplified version of spi_mem_no_dirmap_write() */ + struct spi_mem_op op = desc->info.op_tmpl; + + op.addr.val = desc->info.offset + offs; + op.data.buf.out = buf; + op.data.nbytes = len; + err = spi_mem_exec_op(desc->slave, &op); + if (err) + return err; + + return op.data.nbytes; + } + + /* minimum oob size is 64 */ + bytes = round_up(offs + len, 64); + + opcode = desc->info.op_tmpl.cmd.opcode; + switch (opcode) { + case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: + case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE: + wr_mode = 0; break; - case 4096: - val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x2); + case SPI_NAND_OP_PROGRAM_LOAD_QUAD: + case SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD: + wr_mode = 2; break; default: - val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x0); - break; + /* unknown opcode */ + return -EOPNOTSUPP; } - err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_PAGEFMT, - SPI_NFI_PAGE_SIZE, val); - if (err) + if (offs > 0) + memset(txrx_buf, 0xff, offs); + memcpy(txrx_buf + offs, buf, len); + if (bytes > offs + len) + memset(txrx_buf + offs + len, 0xff, bytes - offs - len); + + err = airoha_snand_set_mode(priv, SPI_MODE_DMA); + if (err < 0) return err; - /* sec num */ - val = FIELD_PREP(SPI_NFI_SEC_NUM, priv->nfi_cfg.sec_num); + /* NFI reset */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); + if (err) + goto error_dma_mode_off; + + /* + * NFI configure: + * - No AutoFDM (custom sector size (SECCUS) register will be used) + * - No SoC's hardware ECC (flash internal ECC will be used) + * - Use burst mode (faster, but requires 16 byte alignment for addresses) + * - Setup for writing (SPI_NFI_READ_MODE bit is cleared) + * - Setup writing command: FIELD_PREP(SPI_NFI_OPMODE, 3) + * - Use DMA instead of PIO for data writing + */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_DMA_MODE | + SPI_NFI_READ_MODE | + SPI_NFI_DMA_BURST_EN | + SPI_NFI_HW_ECC_EN | + SPI_NFI_AUTO_FDM_EN | + SPI_NFI_OPMODE, + SPI_NFI_DMA_MODE | + SPI_NFI_DMA_BURST_EN | + FIELD_PREP(SPI_NFI_OPMODE, 3)); + if (err) + goto error_dma_mode_off; + + /* Set number of sector will be written */ err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_CON, - SPI_NFI_SEC_NUM, val); + SPI_NFI_SEC_NUM, + FIELD_PREP(SPI_NFI_SEC_NUM, 1)); if (err) - return err; + goto error_dma_mode_off; - /* enable cust sec size */ - err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, - SPI_NFI_CUS_SEC_SIZE_EN); + /* Set custom sector size */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE | + SPI_NFI_CUS_SEC_SIZE_EN, + FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) | + SPI_NFI_CUS_SEC_SIZE_EN); if (err) - return err; + goto error_dma_mode_off; - /* set cust sec size */ - val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, priv->nfi_cfg.sec_size); - return regmap_update_bits(priv->regmap_nfi, - REG_SPI_NFI_SECCUS_SIZE, - SPI_NFI_CUS_SEC_SIZE, val); -} + dma_addr = dma_map_single(txrx_buf, SPI_NAND_CACHE_SIZE, + DMA_TO_DEVICE); -static int airoha_snand_adjust_op_size(struct spi_slave *slave, - struct spi_mem_op *op) -{ - size_t max_len; + /* set dma addr */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_STRADDR, + dma_addr); + if (err) + goto error_dma_unmap; - max_len = 1 + op->addr.nbytes + op->dummy.nbytes; - if (max_len >= 160) - return -EOPNOTSUPP; + /* + * Setup transfer length + * --------------------- + * The following rule MUST be met: + * transfer_length = + * = NFI_SNF_MISC_CTL2.write_data_byte_number = + * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size + */ + err = regmap_update_bits(priv->regmap_nfi, + REG_SPI_NFI_SNF_MISC_CTL2, + SPI_NFI_PROG_LOAD_BYTE_NUM, + FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, bytes)); + if (err) + goto error_dma_unmap; - if (op->data.nbytes > 160 - max_len) - op->data.nbytes = 160 - max_len; + /* set write command */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_PG_CTL1, + FIELD_PREP(SPI_NFI_PG_LOAD_CMD, opcode)); + if (err) + goto error_dma_unmap; - return 0; -} + /* set write mode */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, + FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode)); + if (err) + goto error_dma_unmap; -static bool airoha_snand_supports_op(struct spi_slave *slave, - const struct spi_mem_op *op) -{ - if (!spi_mem_default_supports_op(slave, op)) - return false; + /* set write addr: zero page offset + descriptor write offset */ + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_PG_CTL2, + desc->info.offset); + if (err) + goto error_dma_unmap; - if (op->cmd.buswidth != 1) - return false; + err = regmap_write(priv->regmap_nfi, REG_SPI_NFI_CMD, 0x80); + if (err) + goto error_dma_unmap; - return (!op->addr.nbytes || op->addr.buswidth == 1) && - (!op->dummy.nbytes || op->dummy.buswidth == 1) && - (!op->data.nbytes || op->data.buswidth == 1); + /* trigger dma writing */ + err = regmap_clear_bits(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_WR_TRIG); + if (err) + goto error_dma_unmap; + + err = regmap_set_bits(priv->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_WR_TRIG); + if (err) + goto error_dma_unmap; + + err = regmap_read_poll_timeout(priv->regmap_nfi, REG_SPI_NFI_INTR, + val, (val & SPI_NFI_AHB_DONE), 0, + 1 * MSEC_PER_SEC); + if (err) + goto error_dma_unmap; + + err = regmap_read_poll_timeout(priv->regmap_nfi, + REG_SPI_NFI_SNF_STA_CTL1, val, + (val & SPI_NFI_LOAD_TO_CACHE_DONE), + 0, 1 * MSEC_PER_SEC); + if (err) + goto error_dma_unmap; + + /* + * SPI_NFI_LOAD_TO_CACHE_DONE bit must be written at the end + * of dirmap_write operation even if it is already set. + */ + err = regmap_update_bits(priv->regmap_nfi, REG_SPI_NFI_SNF_STA_CTL1, + SPI_NFI_LOAD_TO_CACHE_DONE, + SPI_NFI_LOAD_TO_CACHE_DONE); + if (err) + goto error_dma_unmap; + + dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_TO_DEVICE); + + err = airoha_snand_set_mode(priv, SPI_MODE_MANUAL); + if (err < 0) + return err; + + return len; + +error_dma_unmap: + dma_unmap_single(dma_addr, SPI_NAND_CACHE_SIZE, DMA_TO_DEVICE); +error_dma_mode_off: + airoha_snand_set_mode(priv, SPI_MODE_MANUAL); + return err; } static int airoha_snand_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) { - u8 data[8], cmd, opcode = op->cmd.opcode; struct udevice *bus = slave->dev->parent; struct airoha_snand_priv *priv; + int op_len, addr_len, dummy_len; + u8 buf[20], *data; int i, err; priv = dev_get_priv(bus); + op_len = op->cmd.nbytes; + addr_len = op->addr.nbytes; + dummy_len = op->dummy.nbytes; + + if (op_len + dummy_len + addr_len > sizeof(buf)) + return -EIO; + + data = buf; + for (i = 0; i < op_len; i++) + *data++ = op->cmd.opcode >> (8 * (op_len - i - 1)); + for (i = 0; i < addr_len; i++) + *data++ = op->addr.val >> (8 * (addr_len - i - 1)); + for (i = 0; i < dummy_len; i++) + *data++ = 0xff; + /* switch to manual mode */ err = airoha_snand_set_mode(priv, SPI_MODE_MANUAL); if (err < 0) @@ -574,40 +982,40 @@ static int airoha_snand_exec_op(struct spi_slave *slave, return err; /* opcode */ - err = airoha_snand_write_data(priv, 0x8, &opcode, sizeof(opcode)); + data = buf; + err = airoha_snand_write_data(priv, data, op_len, + op->cmd.buswidth); if (err) return err; /* addr part */ - cmd = opcode == SPI_NAND_OP_GET_FEATURE ? 0x11 : 0x8; - put_unaligned_be64(op->addr.val, data); - - for (i = ARRAY_SIZE(data) - op->addr.nbytes; - i < ARRAY_SIZE(data); i++) { - err = airoha_snand_write_data(priv, cmd, &data[i], - sizeof(data[0])); + data += op_len; + if (addr_len) { + err = airoha_snand_write_data(priv, data, addr_len, + op->addr.buswidth); if (err) return err; } /* dummy */ - data[0] = 0xff; - for (i = 0; i < op->dummy.nbytes; i++) { - err = airoha_snand_write_data(priv, 0x8, &data[0], - sizeof(data[0])); + data += addr_len; + if (dummy_len) { + err = airoha_snand_write_data(priv, data, dummy_len, + op->dummy.buswidth); if (err) return err; } /* data */ - if (op->data.dir == SPI_MEM_DATA_IN) { - err = airoha_snand_read_data(priv, op->data.buf.in, - op->data.nbytes); - if (err) - return err; - } else { - err = airoha_snand_write_data(priv, 0x8, op->data.buf.out, - op->data.nbytes); + if (op->data.nbytes) { + if (op->data.dir == SPI_MEM_DATA_IN) + err = airoha_snand_read_data(priv, op->data.buf.in, + op->data.nbytes, + op->data.buswidth); + else + err = airoha_snand_write_data(priv, op->data.buf.out, + op->data.nbytes, + op->data.buswidth); if (err) return err; } @@ -619,6 +1027,13 @@ static int airoha_snand_probe(struct udevice *dev) { struct airoha_snand_priv *priv = dev_get_priv(dev); int ret; + u32 sfc_strap; + + priv->txrx_buf = memalign(ARCH_DMA_MINALIGN, SPI_NAND_CACHE_SIZE); + if (!priv->txrx_buf) { + dev_err(dev, "failed to alloacate memory for dirmap\n"); + return -ENOMEM; + } ret = regmap_init_mem_index(dev_ofnode(dev), &priv->regmap_ctrl, 0); if (ret) { @@ -639,6 +1054,25 @@ static int airoha_snand_probe(struct udevice *dev) } clk_enable(priv->spi_clk); + priv->dma = 1; + if (device_is_compatible(dev, "airoha,en7523-snand")){ + ret = regmap_read(priv->regmap_ctrl, REG_SPI_CTRL_SFC_STRAP, &sfc_strap); + if (ret) + return ret; + + if (!(sfc_strap & 0x04)) { + priv->dma = 0; + printf("\n" + "=== WARNING ======================================================\n" + "Detected booting in RESERVED mode (UART_TXD was short to GND).\n" + "This mode is known for incorrect DMA reading of some flashes.\n" + "Usage of DMA for flash operations will be disabled to prevent data\n" + "damage. Unplug your serial console and power cycle the board\n" + "to boot with full performance.\n" + "==================================================================\n\n"); + } + } + return airoha_snand_nfi_init(priv); } @@ -659,48 +1093,18 @@ static int airoha_snand_nfi_set_mode(struct udevice *bus, uint mode) return 0; } -static int airoha_snand_nfi_setup(struct spi_slave *slave, - const struct spinand_info *spinand_info) -{ - struct udevice *bus = slave->dev->parent; - struct airoha_snand_priv *priv; - u32 sec_size, sec_num; - int pagesize, oobsize; - - priv = dev_get_priv(bus); - - pagesize = spinand_info->memorg.pagesize; - oobsize = spinand_info->memorg.oobsize; - - if (pagesize == 2 * 1024) - sec_num = 4; - else if (pagesize == 4 * 1024) - sec_num = 8; - else - sec_num = 1; - - sec_size = (pagesize + oobsize) / sec_num; - - /* init default value */ - priv->nfi_cfg.sec_size = sec_size; - priv->nfi_cfg.sec_num = sec_num; - priv->nfi_cfg.page_size = round_down(sec_size * sec_num, 1024); - priv->nfi_cfg.spare_size = 16; - - return airoha_snand_nfi_config(priv); -} - static const struct spi_controller_mem_ops airoha_snand_mem_ops = { - .adjust_op_size = airoha_snand_adjust_op_size, .supports_op = airoha_snand_supports_op, .exec_op = airoha_snand_exec_op, + .dirmap_create = airoha_snand_dirmap_create, + .dirmap_read = airoha_snand_dirmap_read, + .dirmap_write = airoha_snand_dirmap_write, }; static const struct dm_spi_ops airoha_snfi_spi_ops = { .mem_ops = &airoha_snand_mem_ops, .set_speed = airoha_snand_nfi_set_speed, .set_mode = airoha_snand_nfi_set_mode, - .setup_for_spinand = airoha_snand_nfi_setup, }; static const struct udevice_id airoha_snand_ids[] = { diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index db44a7b26eb..3fd2353af94 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -499,6 +499,31 @@ int spi_mem_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op) } EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size); +static inline u64 spi_mem_bytes_to_ncycles(u32 nbytes, u8 buswidth, u8 dtr) +{ + u64 ncycles; + u32 divider = buswidth * (dtr ? 2 : 1); + + /* + * Theoretically + * + * ncycles = (nbytes * 8) / (buswidth * (dtr ? 2 : 1)); + * + * may lead to an integer overflow, if nbytes will be larger than + * 0x1fffffff. Lets split this operation on: + * + * 1) Operation with bits 0..28 (overflow will not happen), + * + * 2) Operation with bits 29..31. Here we'll take into account + * that buswidth is a small power of 2 (so whole divider is + * small power of 2). Hense we may divide first, then multiply. + */ + ncycles = ((nbytes & 0x1fffffff) * 8) / divider; + ncycles += ((u64) ((nbytes & ~0x1fffffff) / divider)) * 8; + + return ncycles; +} + /** * spi_mem_calc_op_duration() - Derives the theoretical length (in cpu cycles) * of an operation. This helps finding the best @@ -518,14 +543,22 @@ u64 spi_mem_calc_op_duration(struct spi_mem_op *op) { u64 ncycles = 0; - ncycles += ((op->cmd.nbytes * 8) / op->cmd.buswidth) / (op->cmd.dtr ? 2 : 1); - ncycles += ((op->addr.nbytes * 8) / op->addr.buswidth) / (op->addr.dtr ? 2 : 1); + ncycles += spi_mem_bytes_to_ncycles(op->cmd.nbytes, + op->cmd.buswidth, + op->cmd.dtr); + ncycles += spi_mem_bytes_to_ncycles(op->addr.nbytes, + op->addr.buswidth, + op->addr.dtr); /* Dummy bytes are optional for some SPI flash memory operations */ if (op->dummy.nbytes) - ncycles += ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1); + ncycles += spi_mem_bytes_to_ncycles(op->dummy.nbytes, + op->dummy.buswidth, + op->dummy.dtr); - ncycles += ((op->data.nbytes * 8) / op->data.buswidth) / (op->data.dtr ? 2 : 1); + ncycles += spi_mem_bytes_to_ncycles(op->data.nbytes, + op->data.buswidth, + op->data.dtr); return ncycles; } diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig index 68693b7d226..445270e8da1 100644 --- a/drivers/ufs/Kconfig +++ b/drivers/ufs/Kconfig @@ -15,20 +15,6 @@ config CADENCE_UFS This selects the platform driver for the Cadence UFS host controller present on present TI's J721e devices. -config UFS_MEDIATEK - tristate "MediaTek UFS Host Controller Driver" - depends on UFS && ARCH_MEDIATEK - select PHY_MTK_UFS - help - This selects the MediaTek specific additions to UFSHCD platform driver. - UFS host on Mediatek needs some vendor specific configuration before - accessing the hardware which includes PHY configuration and vendor - specific registers. - - Select this if you have UFS controller on MediaTek chipset. - - If unsure, say N. - config QCOM_UFS bool "Qualcomm Host Controller driver for UFS" depends on UFS && ARCH_SNAPDRAGON @@ -59,6 +45,20 @@ config UFS_AMD_VERSAL2 UFS host on AMD needs some vendor specific configuration before accessing the hardware. +config UFS_MEDIATEK + tristate "MediaTek UFS Host Controller Driver" + depends on UFS && ARCH_MEDIATEK + select PHY_MTK_UFS + help + This selects the MediaTek specific additions to UFSHCD platform driver. + UFS host on Mediatek needs some vendor specific configuration before + accessing the hardware which includes PHY configuration and vendor + specific registers. + + Select this if you have UFS controller on MediaTek chipset. + + If unsure, say N. + config UFS_PCI bool "PCI bus based UFS Controller support" depends on PCI && UFS diff --git a/drivers/ufs/Makefile b/drivers/ufs/Makefile index 15329b9795a..6b2f2ccc9fc 100644 --- a/drivers/ufs/Makefile +++ b/drivers/ufs/Makefile @@ -5,11 +5,11 @@ obj-$(CONFIG_UFS) += ufs-uclass.o obj-$(CONFIG_CADENCE_UFS) += cdns-platform.o -obj-$(CONFIG_UFS_MEDIATEK) += ufs-mediatek.o obj-$(CONFIG_QCOM_UFS) += ufs-qcom.o +obj-$(CONFIG_ROCKCHIP_UFS) += ufs-rockchip.o obj-$(CONFIG_TI_J721E_UFS) += ti-j721e-ufs.o obj-$(CONFIG_UFS_AMD_VERSAL2) += ufs-amd-versal2.o ufshcd-dwc.o +obj-$(CONFIG_UFS_MEDIATEK) += ufs-mediatek.o obj-$(CONFIG_UFS_PCI) += ufs-pci.o obj-$(CONFIG_UFS_RENESAS) += ufs-renesas.o obj-$(CONFIG_UFS_RENESAS_GEN5) += ufs-renesas-rcar-gen5.o -obj-$(CONFIG_ROCKCHIP_UFS) += ufs-rockchip.o diff --git a/drivers/ufs/ufs-renesas-rcar-gen5.c b/drivers/ufs/ufs-renesas-rcar-gen5.c index 3c66022579f..cc53e91449c 100644 --- a/drivers/ufs/ufs-renesas-rcar-gen5.c +++ b/drivers/ufs/ufs-renesas-rcar-gen5.c @@ -258,7 +258,7 @@ static const struct udevice_id ufs_renesas_pltfm_ids[] = { { /* sentinel */ } }; -U_BOOT_DRIVER(ufs_renesas) = { +U_BOOT_DRIVER(ufs_renesas_gen5) = { .name = "ufs-renesas-gen5", .id = UCLASS_UFS, .of_match = ufs_renesas_pltfm_ids, diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index daf2240ffd9..93c5ee69b25 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -78,8 +78,6 @@ source "drivers/usb/dwc3/Kconfig" source "drivers/usb/mtu3/Kconfig" -source "drivers/usb/musb/Kconfig" - source "drivers/usb/musb-new/Kconfig" source "drivers/usb/emul/Kconfig" diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 008f8c99a58..7e08aeab904 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -39,6 +39,7 @@ menuconfig USB_GADGET config SPL_USB_GADGET bool "USB Gadget Support in SPL" + depends on SPL_FRAMEWORK help Enable USB Gadget API which allows to enable USB device functions in SPL. @@ -107,6 +108,7 @@ config USB_GADGET_AT91 config USB_GADGET_DWC2_OTG bool "DesignWare USB2.0 HS OTG controller (gadget mode)" + depends on ARM select USB_GADGET_DUALSPEED help The Designware USB2.0 high-speed gadget controller @@ -149,6 +151,7 @@ config USB_GADGET_OS_DESCRIPTORS config CI_UDC bool "ChipIdea device controller" + depends on !DM_USB_GADGET select USB_GADGET_DUALSPEED help Say Y here to enable device controller functionality of the diff --git a/drivers/usb/host/xhci-brcm.c b/drivers/usb/host/xhci-brcm.c index 2ffad148dea..595839fac3c 100644 --- a/drivers/usb/host/xhci-brcm.c +++ b/drivers/usb/host/xhci-brcm.c @@ -85,7 +85,7 @@ static const struct udevice_id xhci_brcm_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_brcm) = { .name = "xhci_brcm", .id = UCLASS_USB, .probe = xhci_brcm_probe, diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c index c509ce1620a..500696ccae7 100644 --- a/drivers/usb/host/xhci-exynos5.c +++ b/drivers/usb/host/xhci-exynos5.c @@ -246,7 +246,7 @@ static const struct udevice_id xhci_usb_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_exynos) = { .name = "xhci_exynos", .id = UCLASS_USB, .of_match = xhci_usb_ids, diff --git a/drivers/usb/host/xhci-generic.c b/drivers/usb/host/xhci-generic.c index 355d4883176..8bb4e277423 100644 --- a/drivers/usb/host/xhci-generic.c +++ b/drivers/usb/host/xhci-generic.c @@ -61,7 +61,7 @@ static const struct udevice_id xhci_usb_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_generic) = { .name = "xhci_generic", .id = UCLASS_USB, .of_match = xhci_usb_ids, diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 7e288f0575b..ffe80c0bbdc 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -357,7 +357,7 @@ static const struct udevice_id xhci_mtk_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_mtk) = { .name = "xhci-mtk", .id = UCLASS_USB, .of_match = xhci_mtk_ids, diff --git a/drivers/usb/host/xhci-mvebu.c b/drivers/usb/host/xhci-mvebu.c index 1338b1021c6..12dc61aee9d 100644 --- a/drivers/usb/host/xhci-mvebu.c +++ b/drivers/usb/host/xhci-mvebu.c @@ -87,7 +87,7 @@ static const struct udevice_id xhci_usb_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_mvebu) = { .name = "xhci_mvebu", .id = UCLASS_USB, .of_match = xhci_usb_ids, diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index b72807053c4..95dfa2c3f87 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -149,7 +149,7 @@ static const struct udevice_id xhci_rcar_ids[] = { { } }; -U_BOOT_DRIVER(usb_xhci) = { +U_BOOT_DRIVER(xhci_rcar) = { .name = "xhci_rcar", .id = UCLASS_USB, .probe = xhci_rcar_probe, diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig deleted file mode 100644 index 2508b6ed0d1..00000000000 --- a/drivers/usb/musb/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# (C) Copyright 2017 -# Adam Ford, Logic PD, [email protected] - -comment "Legacy MUSB Support" - -config USB_MUSB_HCD - bool "Legacy MUSB Host Controller" - -config USB_MUSB_UDC - bool "Legacy USB Device Controller" - -config USB_OMAP3 - bool "Legacy MUSB OMAP3 / OMAP4" - depends on ARCH_OMAP2PLUS - -config USB_AM35X - bool"Legacy MUSB AM35x" - depends on ARCH_OMAP2PLUS && !USB_OMAP3 diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile deleted file mode 100644 index 744f2cfaa29..00000000000 --- a/drivers/usb/musb/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0+ -# -# (C) Copyright 2000-2007 -# Wolfgang Denk, DENX Software Engineering, [email protected]. - -obj-$(CONFIG_USB_MUSB_HCD) += musb_hcd.o musb_core.o -obj-$(CONFIG_USB_MUSB_UDC) += musb_udc.o musb_core.o -obj-$(CONFIG_USB_OMAP3) += omap3.o -obj-$(CONFIG_USB_AM35X) += am35x.o diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c deleted file mode 100644 index 2c23043d40e..00000000000 --- a/drivers/usb/musb/am35x.c +++ /dev/null @@ -1,138 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * am35x.c - TI's AM35x platform specific usb wrapper functions. - * - * Author: Ajay Kumar Gupta <[email protected]> - * - * Based on drivers/usb/musb/da8xx.c - * - * Copyright (c) 2010 Texas Instruments Incorporated - */ - -#include <linux/delay.h> - -#include "am35x.h" - -/* MUSB platform configuration */ -struct musb_config musb_cfg = { - .regs = (struct musb_regs *)AM35X_USB_OTG_CORE_BASE, - .timeout = AM35X_USB_OTG_TIMEOUT, - .musb_speed = 0, -}; - -/* - * Enable the USB phy - */ -static u8 phy_on(void) -{ - u32 devconf2; - u32 timeout; - - devconf2 = readl(&am35x_scm_general_regs->devconf2); - - devconf2 &= ~(DEVCONF2_RESET | DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN | - DEVCONF2_OTGMODE | DEVCONF2_REFFREQ | - DEVCONF2_PHY_GPIOMODE); - devconf2 |= DEVCONF2_SESENDEN | DEVCONF2_VBDTCTEN | DEVCONF2_PHY_PLLON | - DEVCONF2_REFFREQ_13MHZ | DEVCONF2_DATPOL; - - writel(devconf2, &am35x_scm_general_regs->devconf2); - - /* wait until the USB phy is turned on */ - timeout = musb_cfg.timeout; - while (timeout--) - if (readl(&am35x_scm_general_regs->devconf2) & DEVCONF2_PHYCKGD) - return 1; - - /* USB phy was not turned on */ - return 0; -} - -/* - * Disable the USB phy - */ -static void phy_off(void) -{ - u32 devconf2; - - /* - * Power down the on-chip PHY. - */ - devconf2 = readl(&am35x_scm_general_regs->devconf2); - - devconf2 &= ~DEVCONF2_PHY_PLLON; - devconf2 |= DEVCONF2_PHYPWRDN | DEVCONF2_OTGPWRDN; - writel(devconf2, &am35x_scm_general_regs->devconf2); -} - -/* - * This function performs platform specific initialization for usb0. - */ -int musb_platform_init(void) -{ - u32 revision; - u32 sw_reset; - - /* global usb reset */ - sw_reset = readl(&am35x_scm_general_regs->ip_sw_reset); - sw_reset |= (1 << 0); - writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset); - sw_reset &= ~(1 << 0); - writel(sw_reset, &am35x_scm_general_regs->ip_sw_reset); - - /* reset the controller */ - writel(0x1, &am35x_usb_regs->control); - udelay(5000); - - /* start the on-chip usb phy and its pll */ - if (phy_on() == 0) - return -1; - - /* Returns zero if e.g. not clocked */ - revision = readl(&am35x_usb_regs->revision); - if (revision == 0) - return -1; - - return 0; -} - -/* - * This function performs platform specific deinitialization for usb0. - */ -void musb_platform_deinit(void) -{ - /* Turn off the phy */ - phy_off(); -} - -/* - * This function reads data from endpoint fifo for AM35x - * which supports only 32bit read operation. - * - * ep - endpoint number - * length - number of bytes to read from FIFO - * fifo_data - pointer to data buffer into which data is read - */ -__attribute__((weak)) -void read_fifo(u8 ep, u32 length, void *fifo_data) -{ - u8 *data = (u8 *)fifo_data; - u32 val; - int i; - - /* select the endpoint index */ - writeb(ep, &musbr->index); - - if (length > 4) { - for (i = 0; i < (length >> 2); i++) { - val = readl(&musbr->fifox[ep]); - memcpy(data, &val, 4); - data += 4; - } - length %= 4; - } - if (length > 0) { - val = readl(&musbr->fifox[ep]); - memcpy(data, &val, length); - } -} diff --git a/drivers/usb/musb/am35x.h b/drivers/usb/musb/am35x.h deleted file mode 100644 index 82ad94329cb..00000000000 --- a/drivers/usb/musb/am35x.h +++ /dev/null @@ -1,81 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * am35x.h - TI's AM35x platform specific usb wrapper definitions. - * - * Author: Ajay Kumar Gupta <[email protected]> - * - * Based on drivers/usb/musb/da8xx.h - * - * Copyright (c) 2010 Texas Instruments Incorporated - */ - -#ifndef __AM35X_USB_H__ -#define __AM35X_USB_H__ - -#include <asm/arch/am35x_def.h> -#include "musb_core.h" - -/* Base address of musb wrapper */ -#define AM35X_USB_OTG_BASE 0x5C040000 - -/* Base address of musb core */ -#define AM35X_USB_OTG_CORE_BASE (AM35X_USB_OTG_BASE + 0x400) - -/* Timeout for AM35x usb module */ -#define AM35X_USB_OTG_TIMEOUT 0x3FFFFFF - -/* - * AM35x platform USB wrapper register overlay. - */ -struct am35x_usb_regs { - u32 revision; - u32 control; - u32 status; - u32 emulation; - u32 reserved0[1]; - u32 autoreq; - u32 srpfixtime; - u32 ep_intsrc; - u32 ep_intsrcset; - u32 ep_intsrcclr; - u32 ep_intmsk; - u32 ep_intmskset; - u32 ep_intmskclr; - u32 ep_intsrcmsked; - u32 reserved1[1]; - u32 core_intsrc; - u32 core_intsrcset; - u32 core_intsrcclr; - u32 core_intmsk; - u32 core_intmskset; - u32 core_intmskclr; - u32 core_intsrcmsked; - u32 reserved2[1]; - u32 eoi; - u32 mop_sop_en; - u32 reserved3[2]; - u32 txmode; - u32 rxmode; - u32 epcount_mode; -}; - -#define am35x_usb_regs ((struct am35x_usb_regs *)AM35X_USB_OTG_BASE) - -/* USB 2.0 PHY Control */ -#define DEVCONF2_PHY_GPIOMODE (1 << 23) -#define DEVCONF2_OTGMODE (3 << 14) -#define DEVCONF2_SESENDEN (1 << 13) /* Vsess_end comparator */ -#define DEVCONF2_VBDTCTEN (1 << 12) /* Vbus comparator */ -#define DEVCONF2_REFFREQ_24MHZ (2 << 8) -#define DEVCONF2_REFFREQ_26MHZ (7 << 8) -#define DEVCONF2_REFFREQ_13MHZ (6 << 8) -#define DEVCONF2_REFFREQ (0xf << 8) -#define DEVCONF2_PHYCKGD (1 << 7) -#define DEVCONF2_VBUSSENSE (1 << 6) -#define DEVCONF2_PHY_PLLON (1 << 5) /* override PLL suspend */ -#define DEVCONF2_RESET (1 << 4) -#define DEVCONF2_PHYPWRDN (1 << 3) -#define DEVCONF2_OTGPWRDN (1 << 2) -#define DEVCONF2_DATPOL (1 << 1) - -#endif /* __AM35X_USB_H__ */ diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c deleted file mode 100644 index 260552e4dbd..00000000000 --- a/drivers/usb/musb/musb_core.c +++ /dev/null @@ -1,150 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Mentor USB OTG Core functionality common for both Host and Device - * functionality. - * - * Copyright (c) 2008 Texas Instruments - * - * Author: Thomas Abraham [email protected], Texas Instruments - */ - -#include <linux/bitops.h> - -#include "musb_core.h" -struct musb_regs *musbr; - -/* - * program the mentor core to start (enable interrupts, dma, etc.) - */ -void musb_start(void) -{ -#if defined(CONFIG_USB_MUSB_HCD) - u8 devctl; - u8 busctl; -#endif - - /* disable all interrupts */ - writew(0, &musbr->intrtxe); - writew(0, &musbr->intrrxe); - writeb(0, &musbr->intrusbe); - writeb(0, &musbr->testmode); - - /* put into basic highspeed mode and start session */ - writeb(MUSB_POWER_HSENAB, &musbr->power); -#if defined(CONFIG_USB_MUSB_HCD) - /* Program PHY to use EXT VBUS if required */ - if (musb_cfg.extvbus == 1) { - busctl = musb_read_ulpi_buscontrol(musbr); - musb_write_ulpi_buscontrol(musbr, busctl | ULPI_USE_EXTVBUS); - } - - devctl = readb(&musbr->devctl); - writeb(devctl | MUSB_DEVCTL_SESSION, &musbr->devctl); -#endif -} - -#ifdef MUSB_NO_DYNAMIC_FIFO -# define config_fifo(dir, idx, addr) -#else -# define config_fifo(dir, idx, addr) \ - do { \ - writeb(idx, &musbr->dir##fifosz); \ - writew(addr, &musbr->dir##fifoadd); \ - } while (0) -#endif - -/* - * This function configures the endpoint configuration. The musb hcd or musb - * device implementation can use this function to configure the endpoints - * and set the FIFO sizes. Note: The summation of FIFO sizes of all endpoints - * should not be more than the available FIFO size. - * - * epinfo - Pointer to EP configuration table - * cnt - Number of entries in the EP conf table. - */ -void musb_configure_ep(const struct musb_epinfo *epinfo, u8 cnt) -{ - u16 csr; - u16 fifoaddr = 64 >> 3; /* First 64 bytes of FIFO reserved for EP0 */ - u32 fifosize; - u8 idx; - - while (cnt--) { - /* prepare fifosize to write to register */ - fifosize = epinfo->epsize >> 3; - idx = fifosize ? ((ffs(fifosize) - 1) & 0xF) : 0; - - writeb(epinfo->epnum, &musbr->index); - if (epinfo->epdir) { - /* Configure fifo size and fifo base address */ - config_fifo(tx, idx, fifoaddr); - - csr = readw(&musbr->txcsr); - /* clear the data toggle bit */ - writew(csr | MUSB_TXCSR_CLRDATATOG, &musbr->txcsr); - /* Flush fifo if required */ - if (csr & MUSB_TXCSR_TXPKTRDY) - writew(csr | MUSB_TXCSR_FLUSHFIFO, - &musbr->txcsr); - } else { - /* Configure fifo size and fifo base address */ - config_fifo(rx, idx, fifoaddr); - - csr = readw(&musbr->rxcsr); - /* clear the data toggle bit */ - writew(csr | MUSB_RXCSR_CLRDATATOG, &musbr->rxcsr); - /* Flush fifo if required */ - if (csr & MUSB_RXCSR_RXPKTRDY) - writew(csr | MUSB_RXCSR_FLUSHFIFO, - &musbr->rxcsr); - } - fifoaddr += 1 << idx; - epinfo++; - } -} - -/* - * This function writes data to endpoint fifo - * - * ep - endpoint number - * length - number of bytes to write to FIFO - * fifo_data - Pointer to data buffer that contains the data to write - */ -__attribute__((weak)) -void write_fifo(u8 ep, u32 length, void *fifo_data) -{ - u8 *data = (u8 *)fifo_data; - - /* select the endpoint index */ - writeb(ep, &musbr->index); - - /* write the data to the fifo */ - while (length--) - writeb(*data++, &musbr->fifox[ep]); -} - -/* - * AM35x supports only 32bit read operations so - * use seperate read_fifo() function for it. - */ -#ifndef CONFIG_USB_AM35X -/* - * This function reads data from endpoint fifo - * - * ep - endpoint number - * length - number of bytes to read from FIFO - * fifo_data - pointer to data buffer into which data is read - */ -__attribute__((weak)) -void read_fifo(u8 ep, u32 length, void *fifo_data) -{ - u8 *data = (u8 *)fifo_data; - - /* select the endpoint index */ - writeb(ep, &musbr->index); - - /* read the data to the fifo */ - while (length--) - *data++ = readb(&musbr->fifox[ep]); -} -#endif /* CONFIG_USB_AM35X */ diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h deleted file mode 100644 index 47b839c0835..00000000000 --- a/drivers/usb/musb/musb_core.h +++ /dev/null @@ -1,343 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/****************************************************************** - * Copyright 2008 Mentor Graphics Corporation - * Copyright (C) 2008 by Texas Instruments - * - * This file is part of the Inventra Controller Driver for Linux. - ******************************************************************/ - -#ifndef __MUSB_HDRC_DEFS_H__ -#define __MUSB_HDRC_DEFS_H__ - -#include <usb_defs.h> -#include <asm/io.h> - -#define MUSB_EP0_FIFOSIZE 64 /* This is non-configurable */ - -/* EP0 */ -struct musb_ep0_regs { - u16 reserved4; - u16 csr0; - u16 reserved5; - u16 reserved6; - u16 count0; - u8 host_type0; - u8 host_naklimit0; - u8 reserved7; - u8 reserved8; - u8 reserved9; - u8 configdata; -}; - -/* EP 1-15 */ -struct musb_epN_regs { - u16 txmaxp; - u16 txcsr; - u16 rxmaxp; - u16 rxcsr; - u16 rxcount; - u8 txtype; - u8 txinterval; - u8 rxtype; - u8 rxinterval; - u8 reserved0; - u8 fifosize; -}; - -/* Mentor USB core register overlay structure */ -#ifndef musb_regs -struct musb_regs { - /* common registers */ - u8 faddr; - u8 power; - u16 intrtx; - u16 intrrx; - u16 intrtxe; - u16 intrrxe; - u8 intrusb; - u8 intrusbe; - u16 frame; - u8 index; - u8 testmode; - /* indexed registers */ - u16 txmaxp; - u16 txcsr; - u16 rxmaxp; - u16 rxcsr; - u16 rxcount; - u8 txtype; - u8 txinterval; - u8 rxtype; - u8 rxinterval; - u8 reserved0; - u8 fifosize; - /* fifo */ - u32 fifox[16]; - /* OTG, dynamic FIFO, version & vendor registers */ - u8 devctl; - u8 reserved1; - u8 txfifosz; - u8 rxfifosz; - u16 txfifoadd; - u16 rxfifoadd; - u32 vcontrol; - u16 hwvers; - u16 reserved2a[1]; - u8 ulpi_busctl; - u8 reserved2b[1]; - u16 reserved2[3]; - u8 epinfo; - u8 raminfo; - u8 linkinfo; - u8 vplen; - u8 hseof1; - u8 fseof1; - u8 lseof1; - u8 reserved3; - /* target address registers */ - struct musb_tar_regs { - u8 txfuncaddr; - u8 reserved0; - u8 txhubaddr; - u8 txhubport; - u8 rxfuncaddr; - u8 reserved1; - u8 rxhubaddr; - u8 rxhubport; - } tar[16]; - /* - * endpoint registers - * ep0 elements are valid when array index is 0 - * otherwise epN is valid - */ - union musb_ep_regs { - struct musb_ep0_regs ep0; - struct musb_epN_regs epN; - } ep[16]; - -} __attribute__((packed)); -#endif - -/* - * MUSB Register bits - */ - -/* POWER */ -#define MUSB_POWER_ISOUPDATE 0x80 -#define MUSB_POWER_SOFTCONN 0x40 -#define MUSB_POWER_HSENAB 0x20 -#define MUSB_POWER_HSMODE 0x10 -#define MUSB_POWER_RESET 0x08 -#define MUSB_POWER_RESUME 0x04 -#define MUSB_POWER_SUSPENDM 0x02 -#define MUSB_POWER_ENSUSPEND 0x01 -#define MUSB_POWER_HSMODE_SHIFT 4 - -/* INTRUSB */ -#define MUSB_INTR_SUSPEND 0x01 -#define MUSB_INTR_RESUME 0x02 -#define MUSB_INTR_RESET 0x04 -#define MUSB_INTR_BABBLE 0x04 -#define MUSB_INTR_SOF 0x08 -#define MUSB_INTR_CONNECT 0x10 -#define MUSB_INTR_DISCONNECT 0x20 -#define MUSB_INTR_SESSREQ 0x40 -#define MUSB_INTR_VBUSERROR 0x80 /* For SESSION end */ - -/* DEVCTL */ -#define MUSB_DEVCTL_BDEVICE 0x80 -#define MUSB_DEVCTL_FSDEV 0x40 -#define MUSB_DEVCTL_LSDEV 0x20 -#define MUSB_DEVCTL_VBUS 0x18 -#define MUSB_DEVCTL_VBUS_SHIFT 3 -#define MUSB_DEVCTL_HM 0x04 -#define MUSB_DEVCTL_HR 0x02 -#define MUSB_DEVCTL_SESSION 0x01 - -/* ULPI VBUSCONTROL */ -#define ULPI_USE_EXTVBUS 0x01 -#define ULPI_USE_EXTVBUSIND 0x02 - -/* TESTMODE */ -#define MUSB_TEST_FORCE_HOST 0x80 -#define MUSB_TEST_FIFO_ACCESS 0x40 -#define MUSB_TEST_FORCE_FS 0x20 -#define MUSB_TEST_FORCE_HS 0x10 -#define MUSB_TEST_PACKET 0x08 -#define MUSB_TEST_K 0x04 -#define MUSB_TEST_J 0x02 -#define MUSB_TEST_SE0_NAK 0x01 - -/* Allocate for double-packet buffering (effectively doubles assigned _SIZE) */ -#define MUSB_FIFOSZ_DPB 0x10 -/* Allocation size (8, 16, 32, ... 4096) */ -#define MUSB_FIFOSZ_SIZE 0x0f - -/* CSR0 */ -#define MUSB_CSR0_FLUSHFIFO 0x0100 -#define MUSB_CSR0_TXPKTRDY 0x0002 -#define MUSB_CSR0_RXPKTRDY 0x0001 - -/* CSR0 in Peripheral mode */ -#define MUSB_CSR0_P_SVDSETUPEND 0x0080 -#define MUSB_CSR0_P_SVDRXPKTRDY 0x0040 -#define MUSB_CSR0_P_SENDSTALL 0x0020 -#define MUSB_CSR0_P_SETUPEND 0x0010 -#define MUSB_CSR0_P_DATAEND 0x0008 -#define MUSB_CSR0_P_SENTSTALL 0x0004 - -/* CSR0 in Host mode */ -#define MUSB_CSR0_H_DIS_PING 0x0800 -#define MUSB_CSR0_H_WR_DATATOGGLE 0x0400 /* Set to allow setting: */ -#define MUSB_CSR0_H_DATATOGGLE 0x0200 /* Data toggle control */ -#define MUSB_CSR0_H_NAKTIMEOUT 0x0080 -#define MUSB_CSR0_H_STATUSPKT 0x0040 -#define MUSB_CSR0_H_REQPKT 0x0020 -#define MUSB_CSR0_H_ERROR 0x0010 -#define MUSB_CSR0_H_SETUPPKT 0x0008 -#define MUSB_CSR0_H_RXSTALL 0x0004 - -/* CSR0 bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_CSR0_P_WZC_BITS \ - (MUSB_CSR0_P_SENTSTALL) -#define MUSB_CSR0_H_WZC_BITS \ - (MUSB_CSR0_H_NAKTIMEOUT | MUSB_CSR0_H_RXSTALL \ - | MUSB_CSR0_RXPKTRDY) - -/* TxType/RxType */ -#define MUSB_TYPE_SPEED 0xc0 -#define MUSB_TYPE_SPEED_SHIFT 6 -#define MUSB_TYPE_SPEED_HIGH 1 -#define MUSB_TYPE_SPEED_FULL 2 -#define MUSB_TYPE_SPEED_LOW 3 -#define MUSB_TYPE_PROTO 0x30 /* Implicitly zero for ep0 */ -#define MUSB_TYPE_PROTO_SHIFT 4 -#define MUSB_TYPE_REMOTE_END 0xf /* Implicitly zero for ep0 */ -#define MUSB_TYPE_PROTO_BULK 2 -#define MUSB_TYPE_PROTO_INTR 3 - -/* CONFIGDATA */ -#define MUSB_CONFIGDATA_MPRXE 0x80 /* Auto bulk pkt combining */ -#define MUSB_CONFIGDATA_MPTXE 0x40 /* Auto bulk pkt splitting */ -#define MUSB_CONFIGDATA_BIGENDIAN 0x20 -#define MUSB_CONFIGDATA_HBRXE 0x10 /* HB-ISO for RX */ -#define MUSB_CONFIGDATA_HBTXE 0x08 /* HB-ISO for TX */ -#define MUSB_CONFIGDATA_DYNFIFO 0x04 /* Dynamic FIFO sizing */ -#define MUSB_CONFIGDATA_SOFTCONE 0x02 /* SoftConnect */ -#define MUSB_CONFIGDATA_UTMIDW 0x01 /* Data width 0/1 => 8/16bits */ - -/* TXCSR in Peripheral and Host mode */ -#define MUSB_TXCSR_AUTOSET 0x8000 -#define MUSB_TXCSR_MODE 0x2000 -#define MUSB_TXCSR_DMAENAB 0x1000 -#define MUSB_TXCSR_FRCDATATOG 0x0800 -#define MUSB_TXCSR_DMAMODE 0x0400 -#define MUSB_TXCSR_CLRDATATOG 0x0040 -#define MUSB_TXCSR_FLUSHFIFO 0x0008 -#define MUSB_TXCSR_FIFONOTEMPTY 0x0002 -#define MUSB_TXCSR_TXPKTRDY 0x0001 - -/* TXCSR in Peripheral mode */ -#define MUSB_TXCSR_P_ISO 0x4000 -#define MUSB_TXCSR_P_INCOMPTX 0x0080 -#define MUSB_TXCSR_P_SENTSTALL 0x0020 -#define MUSB_TXCSR_P_SENDSTALL 0x0010 -#define MUSB_TXCSR_P_UNDERRUN 0x0004 - -/* TXCSR in Host mode */ -#define MUSB_TXCSR_H_WR_DATATOGGLE 0x0200 -#define MUSB_TXCSR_H_DATATOGGLE 0x0100 -#define MUSB_TXCSR_H_NAKTIMEOUT 0x0080 -#define MUSB_TXCSR_H_RXSTALL 0x0020 -#define MUSB_TXCSR_H_ERROR 0x0004 -#define MUSB_TXCSR_H_DATATOGGLE_SHIFT 8 - -/* TXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_TXCSR_P_WZC_BITS \ - (MUSB_TXCSR_P_INCOMPTX | MUSB_TXCSR_P_SENTSTALL \ - | MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_FIFONOTEMPTY) -#define MUSB_TXCSR_H_WZC_BITS \ - (MUSB_TXCSR_H_NAKTIMEOUT | MUSB_TXCSR_H_RXSTALL \ - | MUSB_TXCSR_H_ERROR | MUSB_TXCSR_FIFONOTEMPTY) - -/* RXCSR in Peripheral and Host mode */ -#define MUSB_RXCSR_AUTOCLEAR 0x8000 -#define MUSB_RXCSR_DMAENAB 0x2000 -#define MUSB_RXCSR_DISNYET 0x1000 -#define MUSB_RXCSR_PID_ERR 0x1000 -#define MUSB_RXCSR_DMAMODE 0x0800 -#define MUSB_RXCSR_INCOMPRX 0x0100 -#define MUSB_RXCSR_CLRDATATOG 0x0080 -#define MUSB_RXCSR_FLUSHFIFO 0x0010 -#define MUSB_RXCSR_DATAERROR 0x0008 -#define MUSB_RXCSR_FIFOFULL 0x0002 -#define MUSB_RXCSR_RXPKTRDY 0x0001 - -/* RXCSR in Peripheral mode */ -#define MUSB_RXCSR_P_ISO 0x4000 -#define MUSB_RXCSR_P_SENTSTALL 0x0040 -#define MUSB_RXCSR_P_SENDSTALL 0x0020 -#define MUSB_RXCSR_P_OVERRUN 0x0004 - -/* RXCSR in Host mode */ -#define MUSB_RXCSR_H_AUTOREQ 0x4000 -#define MUSB_RXCSR_H_WR_DATATOGGLE 0x0400 -#define MUSB_RXCSR_H_DATATOGGLE 0x0200 -#define MUSB_RXCSR_H_RXSTALL 0x0040 -#define MUSB_RXCSR_H_REQPKT 0x0020 -#define MUSB_RXCSR_H_ERROR 0x0004 -#define MUSB_S_RXCSR_H_DATATOGGLE 9 - -/* RXCSR bits to avoid zeroing (write zero clears, write 1 ignored) */ -#define MUSB_RXCSR_P_WZC_BITS \ - (MUSB_RXCSR_P_SENTSTALL | MUSB_RXCSR_P_OVERRUN \ - | MUSB_RXCSR_RXPKTRDY) -#define MUSB_RXCSR_H_WZC_BITS \ - (MUSB_RXCSR_H_RXSTALL | MUSB_RXCSR_H_ERROR \ - | MUSB_RXCSR_DATAERROR | MUSB_RXCSR_RXPKTRDY) - -/* HUBADDR */ -#define MUSB_HUBADDR_MULTI_TT 0x80 - -/* Endpoint configuration information. Note: The value of endpoint fifo size - * element should be either 8,16,32,64,128,256,512,1024,2048 or 4096. Other - * values are not supported - */ -struct musb_epinfo { - u8 epnum; /* endpoint number */ - u8 epdir; /* endpoint direction */ - u16 epsize; /* endpoint FIFO size */ -}; - -/* - * Platform specific MUSB configuration. Any platform using the musb - * functionality should create one instance of this structure in the - * platform specific file. - */ -struct musb_config { - struct musb_regs *regs; - u32 timeout; - u8 musb_speed; - u8 extvbus; -}; - -/* externally defined data */ -extern struct musb_config musb_cfg; -extern struct musb_regs *musbr; - -/* exported functions */ -extern void musb_start(void); -extern void musb_configure_ep(const struct musb_epinfo *epinfo, u8 cnt); -extern void write_fifo(u8 ep, u32 length, void *fifo_data); -extern void read_fifo(u8 ep, u32 length, void *fifo_data); - -static inline u8 musb_read_ulpi_buscontrol(struct musb_regs *musbr) -{ - return readb(&musbr->ulpi_busctl); -} -static inline void musb_write_ulpi_buscontrol(struct musb_regs *musbr, u8 val) -{ - writeb(val, &musbr->ulpi_busctl); -} - -#endif /* __MUSB_HDRC_DEFS_H__ */ diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h deleted file mode 100644 index 2c5e192ab21..00000000000 --- a/drivers/usb/musb/musb_debug.h +++ /dev/null @@ -1,191 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 2009 Wind River Systems, Inc. - * Tom Rix <[email protected]> - */ - -/* Define MUSB_DEBUG before including this file to get debug macros */ -#ifdef MUSB_DEBUG - -#define MUSB_FLAGS_PRINT(v, x, y) \ - if (((v) & MUSB_##x##_##y)) \ - serial_printf("\t\t"#y"\n") - -static inline void musb_print_pwr(u8 b) -{ - serial_printf("\tpower 0x%2.2x\n", b); - MUSB_FLAGS_PRINT(b, POWER, ISOUPDATE); - MUSB_FLAGS_PRINT(b, POWER, SOFTCONN); - MUSB_FLAGS_PRINT(b, POWER, HSENAB); - MUSB_FLAGS_PRINT(b, POWER, HSMODE); - MUSB_FLAGS_PRINT(b, POWER, RESET); - MUSB_FLAGS_PRINT(b, POWER, RESUME); - MUSB_FLAGS_PRINT(b, POWER, SUSPENDM); - MUSB_FLAGS_PRINT(b, POWER, ENSUSPEND); -} - -static inline void musb_print_csr0(u16 w) -{ - serial_printf("\tcsr0 0x%4.4x\n", w); - MUSB_FLAGS_PRINT(w, CSR0, FLUSHFIFO); - MUSB_FLAGS_PRINT(w, CSR0_P, SVDSETUPEND); - MUSB_FLAGS_PRINT(w, CSR0_P, SVDRXPKTRDY); - MUSB_FLAGS_PRINT(w, CSR0_P, SENDSTALL); - MUSB_FLAGS_PRINT(w, CSR0_P, SETUPEND); - MUSB_FLAGS_PRINT(w, CSR0_P, DATAEND); - MUSB_FLAGS_PRINT(w, CSR0_P, SENTSTALL); - MUSB_FLAGS_PRINT(w, CSR0, TXPKTRDY); - MUSB_FLAGS_PRINT(w, CSR0, RXPKTRDY); -} - -static inline void musb_print_intrusb(u8 b) -{ - serial_printf("\tintrusb 0x%2.2x\n", b); - MUSB_FLAGS_PRINT(b, INTR, VBUSERROR); - MUSB_FLAGS_PRINT(b, INTR, SESSREQ); - MUSB_FLAGS_PRINT(b, INTR, DISCONNECT); - MUSB_FLAGS_PRINT(b, INTR, CONNECT); - MUSB_FLAGS_PRINT(b, INTR, SOF); - MUSB_FLAGS_PRINT(b, INTR, RESUME); - MUSB_FLAGS_PRINT(b, INTR, SUSPEND); - - if (b & MUSB_INTR_BABBLE) - serial_printf("\t\tMUSB_INTR_RESET or MUSB_INTR_BABBLE\n"); - -} - -static inline void musb_print_intrtx(u16 w) -{ - serial_printf("\tintrtx 0x%4.4x\n", w); -} - -static inline void musb_print_intrrx(u16 w) -{ - serial_printf("\tintrx 0x%4.4x\n", w); -} - -static inline void musb_print_devctl(u8 b) -{ - serial_printf("\tdevctl 0x%2.2x\n", b); - if (b & MUSB_DEVCTL_BDEVICE) - serial_printf("\t\tB device\n"); - else - serial_printf("\t\tA device\n"); - if (b & MUSB_DEVCTL_FSDEV) - serial_printf("\t\tFast Device -(host mode)\n"); - if (b & MUSB_DEVCTL_LSDEV) - serial_printf("\t\tSlow Device -(host mode)\n"); - if (b & MUSB_DEVCTL_HM) - serial_printf("\t\tHost mode\n"); - else - serial_printf("\t\tPeripherial mode\n"); - if (b & MUSB_DEVCTL_HR) - serial_printf("\t\tHost request started(B device)\n"); - else - serial_printf("\t\tHost request finished(B device)\n"); - if (b & MUSB_DEVCTL_BDEVICE) { - if (b & MUSB_DEVCTL_SESSION) - serial_printf("\t\tStart of session(B device)\n"); - else - serial_printf("\t\tEnd of session(B device)\n"); - } else { - if (b & MUSB_DEVCTL_SESSION) - serial_printf("\t\tStart of session(A device)\n"); - else - serial_printf("\t\tEnd of session(A device)\n"); - } -} - -static inline void musb_print_config(u8 b) -{ - serial_printf("\tconfig 0x%2.2x\n", b); - if (b & MUSB_CONFIGDATA_MPRXE) - serial_printf("\t\tAuto combine rx bulk packets\n"); - if (b & MUSB_CONFIGDATA_MPTXE) - serial_printf("\t\tAuto split tx bulk packets\n"); - if (b & MUSB_CONFIGDATA_BIGENDIAN) - serial_printf("\t\tBig Endian ordering\n"); - else - serial_printf("\t\tLittle Endian ordering\n"); - if (b & MUSB_CONFIGDATA_HBRXE) - serial_printf("\t\tHigh speed rx iso endpoint\n"); - if (b & MUSB_CONFIGDATA_HBTXE) - serial_printf("\t\tHigh speed tx iso endpoint\n"); - if (b & MUSB_CONFIGDATA_DYNFIFO) - serial_printf("\t\tDynamic fifo sizing\n"); - if (b & MUSB_CONFIGDATA_SOFTCONE) - serial_printf("\t\tSoft Connect\n"); - if (b & MUSB_CONFIGDATA_UTMIDW) - serial_printf("\t\t16 bit data width\n"); - else - serial_printf("\t\t8 bit data width\n"); -} - -static inline void musb_print_rxmaxp(u16 w) -{ - serial_printf("\trxmaxp 0x%4.4x\n", w); -} - -static inline void musb_print_rxcsr(u16 w) -{ - serial_printf("\trxcsr 0x%4.4x\n", w); - MUSB_FLAGS_PRINT(w, RXCSR, AUTOCLEAR); - MUSB_FLAGS_PRINT(w, RXCSR, DMAENAB); - MUSB_FLAGS_PRINT(w, RXCSR, DISNYET); - MUSB_FLAGS_PRINT(w, RXCSR, PID_ERR); - MUSB_FLAGS_PRINT(w, RXCSR, DMAMODE); - MUSB_FLAGS_PRINT(w, RXCSR, CLRDATATOG); - MUSB_FLAGS_PRINT(w, RXCSR, FLUSHFIFO); - MUSB_FLAGS_PRINT(w, RXCSR, DATAERROR); - MUSB_FLAGS_PRINT(w, RXCSR, FIFOFULL); - MUSB_FLAGS_PRINT(w, RXCSR, RXPKTRDY); - MUSB_FLAGS_PRINT(w, RXCSR_P, SENTSTALL); - MUSB_FLAGS_PRINT(w, RXCSR_P, SENDSTALL); - MUSB_FLAGS_PRINT(w, RXCSR_P, OVERRUN); - - if (w & MUSB_RXCSR_P_ISO) - serial_printf("\t\tiso mode\n"); - else - serial_printf("\t\tbulk mode\n"); - -} - -static inline void musb_print_txmaxp(u16 w) -{ - serial_printf("\ttxmaxp 0x%4.4x\n", w); -} - -static inline void musb_print_txcsr(u16 w) -{ - serial_printf("\ttxcsr 0x%4.4x\n", w); - MUSB_FLAGS_PRINT(w, TXCSR, TXPKTRDY); - MUSB_FLAGS_PRINT(w, TXCSR, FIFONOTEMPTY); - MUSB_FLAGS_PRINT(w, TXCSR, FLUSHFIFO); - MUSB_FLAGS_PRINT(w, TXCSR, CLRDATATOG); - MUSB_FLAGS_PRINT(w, TXCSR_P, UNDERRUN); - MUSB_FLAGS_PRINT(w, TXCSR_P, SENTSTALL); - MUSB_FLAGS_PRINT(w, TXCSR_P, SENDSTALL); - - if (w & MUSB_TXCSR_MODE) - serial_printf("\t\tTX mode\n"); - else - serial_printf("\t\tRX mode\n"); -} - -#else - -/* stubs */ - -#define musb_print_pwr(b) -#define musb_print_csr0(w) -#define musb_print_intrusb(b) -#define musb_print_intrtx(w) -#define musb_print_intrrx(w) -#define musb_print_devctl(b) -#define musb_print_config(b) -#define musb_print_rxmaxp(w) -#define musb_print_rxcsr(w) -#define musb_print_txmaxp(w) -#define musb_print_txcsr(w) - -#endif /* MUSB_DEBUG */ diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c deleted file mode 100644 index c95c6a48281..00000000000 --- a/drivers/usb/musb/musb_hcd.c +++ /dev/null @@ -1,1161 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Mentor USB OTG Core host controller driver. - * - * Copyright (c) 2008 Texas Instruments - * - * Author: Thomas Abraham [email protected], Texas Instruments - */ - -#include <log.h> -#include <usb.h> -#include <linux/delay.h> -#include "musb_hcd.h" - -/* MSC control transfers */ -#define USB_MSC_BBB_RESET 0xFF -#define USB_MSC_BBB_GET_MAX_LUN 0xFE - -/* Endpoint configuration information */ -static const struct musb_epinfo epinfo[3] = { - {MUSB_BULK_EP, 1, 512}, /* EP1 - Bluk Out - 512 Bytes */ - {MUSB_BULK_EP, 0, 512}, /* EP1 - Bluk In - 512 Bytes */ - {MUSB_INTR_EP, 0, 64} /* EP2 - Interrupt IN - 64 Bytes */ -}; - -/* --- Virtual Root Hub ---------------------------------------------------- */ -#ifdef MUSB_NO_MULTIPOINT -static int rh_devnum; -static u32 port_status; - -#include <usbroothubdes.h> - -#endif - -/* - * This function writes the data toggle value. - */ -static void write_toggle(struct usb_device *dev, u8 ep, u8 dir_out) -{ - u16 toggle = usb_gettoggle(dev, ep, dir_out); - u16 csr; - - if (dir_out) { - csr = readw(&musbr->txcsr); - if (!toggle) { - if (csr & MUSB_TXCSR_MODE) - csr = MUSB_TXCSR_CLRDATATOG; - else - csr = 0; - writew(csr, &musbr->txcsr); - } else { - csr |= MUSB_TXCSR_H_WR_DATATOGGLE; - writew(csr, &musbr->txcsr); - csr |= (toggle << MUSB_TXCSR_H_DATATOGGLE_SHIFT); - writew(csr, &musbr->txcsr); - } - } else { - if (!toggle) { - csr = readw(&musbr->txcsr); - if (csr & MUSB_TXCSR_MODE) - csr = MUSB_RXCSR_CLRDATATOG; - else - csr = 0; - writew(csr, &musbr->rxcsr); - } else { - csr = readw(&musbr->rxcsr); - csr |= MUSB_RXCSR_H_WR_DATATOGGLE; - writew(csr, &musbr->rxcsr); - csr |= (toggle << MUSB_S_RXCSR_H_DATATOGGLE); - writew(csr, &musbr->rxcsr); - } - } -} - -/* - * This function checks if RxStall has occurred on the endpoint. If a RxStall - * has occurred, the RxStall is cleared and 1 is returned. If RxStall has - * not occurred, 0 is returned. - */ -static u8 check_stall(u8 ep, u8 dir_out) -{ - u16 csr; - - /* For endpoint 0 */ - if (!ep) { - csr = readw(&musbr->txcsr); - if (csr & MUSB_CSR0_H_RXSTALL) { - csr &= ~MUSB_CSR0_H_RXSTALL; - writew(csr, &musbr->txcsr); - return 1; - } - } else { /* For non-ep0 */ - if (dir_out) { /* is it tx ep */ - csr = readw(&musbr->txcsr); - if (csr & MUSB_TXCSR_H_RXSTALL) { - csr &= ~MUSB_TXCSR_H_RXSTALL; - writew(csr, &musbr->txcsr); - return 1; - } - } else { /* is it rx ep */ - csr = readw(&musbr->rxcsr); - if (csr & MUSB_RXCSR_H_RXSTALL) { - csr &= ~MUSB_RXCSR_H_RXSTALL; - writew(csr, &musbr->rxcsr); - return 1; - } - } - } - return 0; -} - -/* - * waits until ep0 is ready. Returns 0 if ep is ready, -1 for timeout - * error and -2 for stall. - */ -static int wait_until_ep0_ready(struct usb_device *dev, u32 bit_mask) -{ - u16 csr; - int result = 1; - int timeout = MUSB_TIMEOUT; - - while (result > 0) { - csr = readw(&musbr->txcsr); - if (csr & MUSB_CSR0_H_ERROR) { - csr &= ~MUSB_CSR0_H_ERROR; - writew(csr, &musbr->txcsr); - dev->status = USB_ST_CRC_ERR; - result = -1; - break; - } - - switch (bit_mask) { - case MUSB_CSR0_TXPKTRDY: - if (!(csr & MUSB_CSR0_TXPKTRDY)) { - if (check_stall(MUSB_CONTROL_EP, 0)) { - dev->status = USB_ST_STALLED; - result = -2; - } else - result = 0; - } - break; - - case MUSB_CSR0_RXPKTRDY: - if (check_stall(MUSB_CONTROL_EP, 0)) { - dev->status = USB_ST_STALLED; - result = -2; - } else - if (csr & MUSB_CSR0_RXPKTRDY) - result = 0; - break; - - case MUSB_CSR0_H_REQPKT: - if (!(csr & MUSB_CSR0_H_REQPKT)) { - if (check_stall(MUSB_CONTROL_EP, 0)) { - dev->status = USB_ST_STALLED; - result = -2; - } else - result = 0; - } - break; - } - - /* Check the timeout */ - if (--timeout) - udelay(1); - else { - dev->status = USB_ST_CRC_ERR; - result = -1; - break; - } - } - - return result; -} - -/* - * waits until tx ep is ready. Returns 1 when ep is ready and 0 on error. - */ -static int wait_until_txep_ready(struct usb_device *dev, u8 ep) -{ - u16 csr; - int timeout = MUSB_TIMEOUT; - - do { - if (check_stall(ep, 1)) { - dev->status = USB_ST_STALLED; - return 0; - } - - csr = readw(&musbr->txcsr); - if (csr & MUSB_TXCSR_H_ERROR) { - dev->status = USB_ST_CRC_ERR; - return 0; - } - - /* Check the timeout */ - if (--timeout) - udelay(1); - else { - dev->status = USB_ST_CRC_ERR; - return -1; - } - - } while (csr & MUSB_TXCSR_TXPKTRDY); - return 1; -} - -/* - * waits until rx ep is ready. Returns 1 when ep is ready and 0 on error. - */ -static int wait_until_rxep_ready(struct usb_device *dev, u8 ep) -{ - u16 csr; - int timeout = MUSB_TIMEOUT; - - do { - if (check_stall(ep, 0)) { - dev->status = USB_ST_STALLED; - return 0; - } - - csr = readw(&musbr->rxcsr); - if (csr & MUSB_RXCSR_H_ERROR) { - dev->status = USB_ST_CRC_ERR; - return 0; - } - - /* Check the timeout */ - if (--timeout) - udelay(1); - else { - dev->status = USB_ST_CRC_ERR; - return -1; - } - - } while (!(csr & MUSB_RXCSR_RXPKTRDY)); - return 1; -} - -/* - * This function performs the setup phase of the control transfer - */ -static int ctrlreq_setup_phase(struct usb_device *dev, struct devrequest *setup) -{ - int result; - u16 csr; - - /* write the control request to ep0 fifo */ - write_fifo(MUSB_CONTROL_EP, sizeof(struct devrequest), (void *)setup); - - /* enable transfer of setup packet */ - csr = readw(&musbr->txcsr); - csr |= (MUSB_CSR0_TXPKTRDY|MUSB_CSR0_H_SETUPPKT); - writew(csr, &musbr->txcsr); - - /* wait until the setup packet is transmitted */ - result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); - dev->act_len = 0; - return result; -} - -/* - * This function handles the control transfer in data phase - */ -static int ctrlreq_in_data_phase(struct usb_device *dev, u32 len, void *buffer) -{ - u16 csr; - u32 rxlen = 0; - u32 nextlen = 0; - u8 maxpktsize = (1 << dev->maxpacketsize) * 8; - u8 *rxbuff = (u8 *)buffer; - u8 rxedlength; - int result; - - while (rxlen < len) { - /* Determine the next read length */ - nextlen = ((len-rxlen) > maxpktsize) ? maxpktsize : (len-rxlen); - - /* Set the ReqPkt bit */ - csr = readw(&musbr->txcsr); - writew(csr | MUSB_CSR0_H_REQPKT, &musbr->txcsr); - result = wait_until_ep0_ready(dev, MUSB_CSR0_RXPKTRDY); - if (result < 0) - return result; - - /* Actual number of bytes received by usb */ - rxedlength = readb(&musbr->rxcount); - - /* Read the data from the RxFIFO */ - read_fifo(MUSB_CONTROL_EP, rxedlength, &rxbuff[rxlen]); - - /* Clear the RxPktRdy Bit */ - csr = readw(&musbr->txcsr); - csr &= ~MUSB_CSR0_RXPKTRDY; - writew(csr, &musbr->txcsr); - - /* short packet? */ - if (rxedlength != nextlen) { - dev->act_len += rxedlength; - break; - } - rxlen += nextlen; - dev->act_len = rxlen; - } - return 0; -} - -/* - * This function handles the control transfer out data phase - */ -static int ctrlreq_out_data_phase(struct usb_device *dev, u32 len, void *buffer) -{ - u16 csr; - u32 txlen = 0; - u32 nextlen = 0; - u8 maxpktsize = (1 << dev->maxpacketsize) * 8; - u8 *txbuff = (u8 *)buffer; - int result = 0; - - while (txlen < len) { - /* Determine the next write length */ - nextlen = ((len-txlen) > maxpktsize) ? maxpktsize : (len-txlen); - - /* Load the data to send in FIFO */ - write_fifo(MUSB_CONTROL_EP, txlen, &txbuff[txlen]); - - /* Set TXPKTRDY bit */ - csr = readw(&musbr->txcsr); - - csr |= MUSB_CSR0_TXPKTRDY; - csr |= MUSB_CSR0_H_DIS_PING; - writew(csr, &musbr->txcsr); - result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); - if (result < 0) - break; - - txlen += nextlen; - dev->act_len = txlen; - } - return result; -} - -/* - * This function handles the control transfer out status phase - */ -static int ctrlreq_out_status_phase(struct usb_device *dev) -{ - u16 csr; - int result; - - /* Set the StatusPkt bit */ - csr = readw(&musbr->txcsr); - csr |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_H_STATUSPKT); - csr |= MUSB_CSR0_H_DIS_PING; - writew(csr, &musbr->txcsr); - - /* Wait until TXPKTRDY bit is cleared */ - result = wait_until_ep0_ready(dev, MUSB_CSR0_TXPKTRDY); - return result; -} - -/* - * This function handles the control transfer in status phase - */ -static int ctrlreq_in_status_phase(struct usb_device *dev) -{ - u16 csr; - int result; - - /* Set the StatusPkt bit and ReqPkt bit */ - csr = MUSB_CSR0_H_REQPKT | MUSB_CSR0_H_STATUSPKT; - csr |= MUSB_CSR0_H_DIS_PING; - writew(csr, &musbr->txcsr); - result = wait_until_ep0_ready(dev, MUSB_CSR0_H_REQPKT); - - /* clear StatusPkt bit and RxPktRdy bit */ - csr = readw(&musbr->txcsr); - csr &= ~(MUSB_CSR0_RXPKTRDY | MUSB_CSR0_H_STATUSPKT); - writew(csr, &musbr->txcsr); - return result; -} - -/* - * determines the speed of the device (High/Full/Slow) - */ -static u8 get_dev_speed(struct usb_device *dev) -{ - return (dev->speed == USB_SPEED_HIGH) ? MUSB_TYPE_SPEED_HIGH : - ((dev->speed == USB_SPEED_LOW) ? MUSB_TYPE_SPEED_LOW : - MUSB_TYPE_SPEED_FULL); -} - -/* - * configure the hub address and the port address. - */ -static void config_hub_port(struct usb_device *dev, u8 ep) -{ - u8 chid; - u8 hub; - - /* Find out the nearest parent which is high speed */ - while (dev->parent->parent != NULL) - if (get_dev_speed(dev->parent) != MUSB_TYPE_SPEED_HIGH) - dev = dev->parent; - else - break; - - /* determine the port address at that hub */ - hub = dev->parent->devnum; - for (chid = 0; chid < USB_MAXCHILDREN; chid++) - if (dev->parent->children[chid] == dev) - break; - -#ifndef MUSB_NO_MULTIPOINT - /* configure the hub address and the port address */ - writeb(hub, &musbr->tar[ep].txhubaddr); - writeb((chid + 1), &musbr->tar[ep].txhubport); - writeb(hub, &musbr->tar[ep].rxhubaddr); - writeb((chid + 1), &musbr->tar[ep].rxhubport); -#endif -} - -#ifdef MUSB_NO_MULTIPOINT - -static void musb_port_reset(int do_reset) -{ - u8 power = readb(&musbr->power); - - if (do_reset) { - power &= 0xf0; - writeb(power | MUSB_POWER_RESET, &musbr->power); - port_status |= USB_PORT_STAT_RESET; - port_status &= ~USB_PORT_STAT_ENABLE; - udelay(30000); - } else { - writeb(power & ~MUSB_POWER_RESET, &musbr->power); - - power = readb(&musbr->power); - if (power & MUSB_POWER_HSMODE) - port_status |= USB_PORT_STAT_HIGH_SPEED; - - port_status &= ~(USB_PORT_STAT_RESET | (USB_PORT_STAT_C_CONNECTION << 16)); - port_status |= USB_PORT_STAT_ENABLE - | (USB_PORT_STAT_C_RESET << 16) - | (USB_PORT_STAT_C_ENABLE << 16); - } -} - -/* - * root hub control - */ -static int musb_submit_rh_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, - struct devrequest *cmd) -{ - int leni = transfer_len; - int len = 0; - int stat = 0; - u32 datab[4]; - const u8 *data_buf = (u8 *) datab; - u16 bmRType_bReq; - u16 wValue; - u16 wIndex; - u16 wLength; - u16 int_usb; - - if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) { - debug("Root-Hub submit IRQ: NOT implemented\n"); - return 0; - } - - bmRType_bReq = cmd->requesttype | (cmd->request << 8); - wValue = swap_16(cmd->value); - wIndex = swap_16(cmd->index); - wLength = swap_16(cmd->length); - - debug("--- HUB ----------------------------------------\n"); - debug("submit rh urb, req=%x val=%#x index=%#x len=%d\n", - bmRType_bReq, wValue, wIndex, wLength); - debug("------------------------------------------------\n"); - - switch (bmRType_bReq) { - case RH_GET_STATUS: - debug("RH_GET_STATUS\n"); - - *(__u16 *) data_buf = swap_16(1); - len = 2; - break; - - case RH_GET_STATUS | RH_INTERFACE: - debug("RH_GET_STATUS | RH_INTERFACE\n"); - - *(__u16 *) data_buf = swap_16(0); - len = 2; - break; - - case RH_GET_STATUS | RH_ENDPOINT: - debug("RH_GET_STATUS | RH_ENDPOINT\n"); - - *(__u16 *) data_buf = swap_16(0); - len = 2; - break; - - case RH_GET_STATUS | RH_CLASS: - debug("RH_GET_STATUS | RH_CLASS\n"); - - *(__u32 *) data_buf = swap_32(0); - len = 4; - break; - - case RH_GET_STATUS | RH_OTHER | RH_CLASS: - debug("RH_GET_STATUS | RH_OTHER | RH_CLASS\n"); - - int_usb = readw(&musbr->intrusb); - if (int_usb & MUSB_INTR_CONNECT) { - port_status |= USB_PORT_STAT_CONNECTION - | (USB_PORT_STAT_C_CONNECTION << 16); - port_status |= USB_PORT_STAT_HIGH_SPEED - | USB_PORT_STAT_ENABLE; - } - - if (port_status & USB_PORT_STAT_RESET) - musb_port_reset(0); - - *(__u32 *) data_buf = swap_32(port_status); - len = 4; - break; - - case RH_CLEAR_FEATURE | RH_ENDPOINT: - debug("RH_CLEAR_FEATURE | RH_ENDPOINT\n"); - - switch (wValue) { - case RH_ENDPOINT_STALL: - debug("C_HUB_ENDPOINT_STALL\n"); - len = 0; - break; - } - port_status &= ~(1 << wValue); - break; - - case RH_CLEAR_FEATURE | RH_CLASS: - debug("RH_CLEAR_FEATURE | RH_CLASS\n"); - - switch (wValue) { - case RH_C_HUB_LOCAL_POWER: - debug("C_HUB_LOCAL_POWER\n"); - len = 0; - break; - - case RH_C_HUB_OVER_CURRENT: - debug("C_HUB_OVER_CURRENT\n"); - len = 0; - break; - } - port_status &= ~(1 << wValue); - break; - - case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: - debug("RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS\n"); - - switch (wValue) { - case RH_PORT_ENABLE: - len = 0; - break; - - case RH_PORT_SUSPEND: - len = 0; - break; - - case RH_PORT_POWER: - len = 0; - break; - - case RH_C_PORT_CONNECTION: - len = 0; - break; - - case RH_C_PORT_ENABLE: - len = 0; - break; - - case RH_C_PORT_SUSPEND: - len = 0; - break; - - case RH_C_PORT_OVER_CURRENT: - len = 0; - break; - - case RH_C_PORT_RESET: - len = 0; - break; - - default: - debug("invalid wValue\n"); - stat = USB_ST_STALLED; - } - - port_status &= ~(1 << wValue); - break; - - case RH_SET_FEATURE | RH_OTHER | RH_CLASS: - debug("RH_SET_FEATURE | RH_OTHER | RH_CLASS\n"); - - switch (wValue) { - case RH_PORT_SUSPEND: - len = 0; - break; - - case RH_PORT_RESET: - musb_port_reset(1); - len = 0; - break; - - case RH_PORT_POWER: - len = 0; - break; - - case RH_PORT_ENABLE: - len = 0; - break; - - default: - debug("invalid wValue\n"); - stat = USB_ST_STALLED; - } - - port_status |= 1 << wValue; - break; - - case RH_SET_ADDRESS: - debug("RH_SET_ADDRESS\n"); - - rh_devnum = wValue; - len = 0; - break; - - case RH_GET_DESCRIPTOR: - debug("RH_GET_DESCRIPTOR: %x, %d\n", wValue, wLength); - - switch (wValue) { - case (USB_DT_DEVICE << 8): /* device descriptor */ - len = min_t(unsigned int, - leni, min_t(unsigned int, - sizeof(root_hub_dev_des), - wLength)); - data_buf = root_hub_dev_des; - break; - - case (USB_DT_CONFIG << 8): /* configuration descriptor */ - len = min_t(unsigned int, - leni, min_t(unsigned int, - sizeof(root_hub_config_des), - wLength)); - data_buf = root_hub_config_des; - break; - - case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */ - len = min_t(unsigned int, - leni, min_t(unsigned int, - sizeof(root_hub_str_index0), - wLength)); - data_buf = root_hub_str_index0; - break; - - case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */ - len = min_t(unsigned int, - leni, min_t(unsigned int, - sizeof(root_hub_str_index1), - wLength)); - data_buf = root_hub_str_index1; - break; - - default: - debug("invalid wValue\n"); - stat = USB_ST_STALLED; - } - - break; - - case RH_GET_DESCRIPTOR | RH_CLASS: { - u8 *_data_buf = (u8 *) datab; - debug("RH_GET_DESCRIPTOR | RH_CLASS\n"); - - _data_buf[0] = 0x09; /* min length; */ - _data_buf[1] = 0x29; - _data_buf[2] = 0x1; /* 1 port */ - _data_buf[3] = 0x01; /* per-port power switching */ - _data_buf[3] |= 0x10; /* no overcurrent reporting */ - - /* Corresponds to data_buf[4-7] */ - _data_buf[4] = 0; - _data_buf[5] = 5; - _data_buf[6] = 0; - _data_buf[7] = 0x02; - _data_buf[8] = 0xff; - - len = min_t(unsigned int, leni, - min_t(unsigned int, data_buf[0], wLength)); - break; - } - - case RH_GET_CONFIGURATION: - debug("RH_GET_CONFIGURATION\n"); - - *(__u8 *) data_buf = 0x01; - len = 1; - break; - - case RH_SET_CONFIGURATION: - debug("RH_SET_CONFIGURATION\n"); - - len = 0; - break; - - default: - debug("*** *** *** unsupported root hub command *** *** ***\n"); - stat = USB_ST_STALLED; - } - - len = min_t(int, len, leni); - if (buffer != data_buf) - memcpy(buffer, data_buf, len); - - dev->act_len = len; - dev->status = stat; - debug("dev act_len %d, status %lu\n", dev->act_len, dev->status); - - return stat; -} - -static void musb_rh_init(void) -{ - rh_devnum = 0; - port_status = 0; -} - -#else - -static void musb_rh_init(void) {} - -#endif - -/* - * do a control transfer - */ -int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int len, struct devrequest *setup) -{ - int devnum = usb_pipedevice(pipe); - u8 devspeed; - -#ifdef MUSB_NO_MULTIPOINT - /* Control message is for the HUB? */ - if (devnum == rh_devnum) { - int stat = musb_submit_rh_msg(dev, pipe, buffer, len, setup); - if (stat) - return stat; - } -#endif - - /* select control endpoint */ - writeb(MUSB_CONTROL_EP, &musbr->index); - readw(&musbr->txcsr); - -#ifndef MUSB_NO_MULTIPOINT - /* target addr and (for multipoint) hub addr/port */ - writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].txfuncaddr); - writeb(devnum, &musbr->tar[MUSB_CONTROL_EP].rxfuncaddr); -#endif - - /* configure the hub address and the port number as required */ - devspeed = get_dev_speed(dev); - if ((musb_ishighspeed()) && (dev->parent != NULL) && - (devspeed != MUSB_TYPE_SPEED_HIGH)) { - config_hub_port(dev, MUSB_CONTROL_EP); - writeb(devspeed << 6, &musbr->txtype); - } else { - writeb(musb_cfg.musb_speed << 6, &musbr->txtype); -#ifndef MUSB_NO_MULTIPOINT - writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubaddr); - writeb(0, &musbr->tar[MUSB_CONTROL_EP].txhubport); - writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubaddr); - writeb(0, &musbr->tar[MUSB_CONTROL_EP].rxhubport); -#endif - } - - /* Control transfer setup phase */ - if (ctrlreq_setup_phase(dev, setup) < 0) - return 0; - - switch (setup->request) { - case USB_REQ_GET_DESCRIPTOR: - case USB_REQ_GET_CONFIGURATION: - case USB_REQ_GET_INTERFACE: - case USB_REQ_GET_STATUS: - case USB_MSC_BBB_GET_MAX_LUN: - /* control transfer in-data-phase */ - if (ctrlreq_in_data_phase(dev, len, buffer) < 0) - return 0; - /* control transfer out-status-phase */ - if (ctrlreq_out_status_phase(dev) < 0) - return 0; - break; - - case USB_REQ_SET_ADDRESS: - case USB_REQ_SET_CONFIGURATION: - case USB_REQ_SET_FEATURE: - case USB_REQ_SET_INTERFACE: - case USB_REQ_CLEAR_FEATURE: - case USB_MSC_BBB_RESET: - /* control transfer in status phase */ - if (ctrlreq_in_status_phase(dev) < 0) - return 0; - break; - - case USB_REQ_SET_DESCRIPTOR: - /* control transfer out data phase */ - if (ctrlreq_out_data_phase(dev, len, buffer) < 0) - return 0; - /* control transfer in status phase */ - if (ctrlreq_in_status_phase(dev) < 0) - return 0; - break; - - default: - /* unhandled control transfer */ - return -1; - } - - dev->status = 0; - dev->act_len = len; - -#ifdef MUSB_NO_MULTIPOINT - /* Set device address to USB_FADDR register */ - if (setup->request == USB_REQ_SET_ADDRESS) - writeb(dev->devnum, &musbr->faddr); -#endif - - return len; -} - -/* - * do a bulk transfer - */ -int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int len) -{ - int dir_out = usb_pipeout(pipe); - int ep = usb_pipeendpoint(pipe); -#ifndef MUSB_NO_MULTIPOINT - int devnum = usb_pipedevice(pipe); -#endif - u8 type; - u16 csr; - u32 txlen = 0; - u32 nextlen = 0; - u8 devspeed; - - /* select bulk endpoint */ - writeb(MUSB_BULK_EP, &musbr->index); - -#ifndef MUSB_NO_MULTIPOINT - /* write the address of the device */ - if (dir_out) - writeb(devnum, &musbr->tar[MUSB_BULK_EP].txfuncaddr); - else - writeb(devnum, &musbr->tar[MUSB_BULK_EP].rxfuncaddr); -#endif - - /* configure the hub address and the port number as required */ - devspeed = get_dev_speed(dev); - if ((musb_ishighspeed()) && (dev->parent != NULL) && - (devspeed != MUSB_TYPE_SPEED_HIGH)) { - /* - * MUSB is in high speed and the destination device is full - * speed device. So configure the hub address and port - * address registers. - */ - config_hub_port(dev, MUSB_BULK_EP); - } else { -#ifndef MUSB_NO_MULTIPOINT - if (dir_out) { - writeb(0, &musbr->tar[MUSB_BULK_EP].txhubaddr); - writeb(0, &musbr->tar[MUSB_BULK_EP].txhubport); - } else { - writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubaddr); - writeb(0, &musbr->tar[MUSB_BULK_EP].rxhubport); - } -#endif - devspeed = musb_cfg.musb_speed; - } - - /* Write the saved toggle bit value */ - write_toggle(dev, ep, dir_out); - - if (dir_out) { /* bulk-out transfer */ - /* Program the TxType register */ - type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | - (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) | - (ep & MUSB_TYPE_REMOTE_END); - writeb(type, &musbr->txtype); - - /* Write maximum packet size to the TxMaxp register */ - writew(dev->epmaxpacketout[ep], &musbr->txmaxp); - while (txlen < len) { - nextlen = ((len-txlen) < dev->epmaxpacketout[ep]) ? - (len-txlen) : dev->epmaxpacketout[ep]; - - /* Write the data to the FIFO */ - write_fifo(MUSB_BULK_EP, nextlen, - (void *)(((u8 *)buffer) + txlen)); - - /* Set the TxPktRdy bit */ - csr = readw(&musbr->txcsr); - writew(csr | MUSB_TXCSR_TXPKTRDY, &musbr->txcsr); - - /* Wait until the TxPktRdy bit is cleared */ - if (wait_until_txep_ready(dev, MUSB_BULK_EP) != 1) { - readw(&musbr->txcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); - dev->act_len = txlen; - return 0; - } - txlen += nextlen; - } - - /* Keep a copy of the data toggle bit */ - csr = readw(&musbr->txcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_TXCSR_H_DATATOGGLE_SHIFT) & 1); - } else { /* bulk-in transfer */ - /* Write the saved toggle bit value */ - write_toggle(dev, ep, dir_out); - - /* Program the RxType register */ - type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | - (MUSB_TYPE_PROTO_BULK << MUSB_TYPE_PROTO_SHIFT) | - (ep & MUSB_TYPE_REMOTE_END); - writeb(type, &musbr->rxtype); - - /* Write the maximum packet size to the RxMaxp register */ - writew(dev->epmaxpacketin[ep], &musbr->rxmaxp); - while (txlen < len) { - nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ? - (len-txlen) : dev->epmaxpacketin[ep]; - - /* Set the ReqPkt bit */ - csr = readw(&musbr->rxcsr); - writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); - - /* Wait until the RxPktRdy bit is set */ - if (wait_until_rxep_ready(dev, MUSB_BULK_EP) != 1) { - csr = readw(&musbr->rxcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); - csr &= ~MUSB_RXCSR_RXPKTRDY; - writew(csr, &musbr->rxcsr); - dev->act_len = txlen; - return 0; - } - - /* Read the data from the FIFO */ - read_fifo(MUSB_BULK_EP, nextlen, - (void *)(((u8 *)buffer) + txlen)); - - /* Clear the RxPktRdy bit */ - csr = readw(&musbr->rxcsr); - csr &= ~MUSB_RXCSR_RXPKTRDY; - writew(csr, &musbr->rxcsr); - txlen += nextlen; - } - - /* Keep a copy of the data toggle bit */ - csr = readw(&musbr->rxcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); - } - - /* bulk transfer is complete */ - dev->status = 0; - dev->act_len = len; - return 0; -} - -/* - * This function initializes the usb controller module. - */ -int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) -{ - u8 power; - u32 timeout; - - musb_rh_init(); - - if (musb_platform_init() == -1) - return -1; - - /* Configure all the endpoint FIFO's and start usb controller */ - musbr = musb_cfg.regs; - musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo)); - musb_start(); - - /* - * Wait until musb is enabled in host mode with a timeout. There - * should be a usb device connected. - */ - timeout = musb_cfg.timeout; - while (--timeout) - if (readb(&musbr->devctl) & MUSB_DEVCTL_HM) - break; - - /* if musb core is not in host mode, then return */ - if (!timeout) - return -1; - - /* start usb bus reset */ - power = readb(&musbr->power); - writeb(power | MUSB_POWER_RESET, &musbr->power); - - /* After initiating a usb reset, wait for about 20ms to 30ms */ - udelay(30000); - - /* stop usb bus reset */ - power = readb(&musbr->power); - power &= ~MUSB_POWER_RESET; - writeb(power, &musbr->power); - - /* Determine if the connected device is a high/full/low speed device */ - musb_cfg.musb_speed = (readb(&musbr->power) & MUSB_POWER_HSMODE) ? - MUSB_TYPE_SPEED_HIGH : - ((readb(&musbr->devctl) & MUSB_DEVCTL_FSDEV) ? - MUSB_TYPE_SPEED_FULL : MUSB_TYPE_SPEED_LOW); - return 0; -} - -/* - * This function stops the operation of the davinci usb module. - */ -int usb_lowlevel_stop(int index) -{ - /* Reset the USB module */ - musb_platform_deinit(); - writeb(0, &musbr->devctl); - return 0; -} - -/* - * This function supports usb interrupt transfers. Currently, usb interrupt - * transfers are not supported. - */ -int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int len, int interval, bool nonblock) -{ - int dir_out = usb_pipeout(pipe); - int ep = usb_pipeendpoint(pipe); -#ifndef MUSB_NO_MULTIPOINT - int devnum = usb_pipedevice(pipe); -#endif - u8 type; - u16 csr; - u32 txlen = 0; - u32 nextlen = 0; - u8 devspeed; - - /* select interrupt endpoint */ - writeb(MUSB_INTR_EP, &musbr->index); - -#ifndef MUSB_NO_MULTIPOINT - /* write the address of the device */ - if (dir_out) - writeb(devnum, &musbr->tar[MUSB_INTR_EP].txfuncaddr); - else - writeb(devnum, &musbr->tar[MUSB_INTR_EP].rxfuncaddr); -#endif - - /* configure the hub address and the port number as required */ - devspeed = get_dev_speed(dev); - if ((musb_ishighspeed()) && (dev->parent != NULL) && - (devspeed != MUSB_TYPE_SPEED_HIGH)) { - /* - * MUSB is in high speed and the destination device is full - * speed device. So configure the hub address and port - * address registers. - */ - config_hub_port(dev, MUSB_INTR_EP); - } else { -#ifndef MUSB_NO_MULTIPOINT - if (dir_out) { - writeb(0, &musbr->tar[MUSB_INTR_EP].txhubaddr); - writeb(0, &musbr->tar[MUSB_INTR_EP].txhubport); - } else { - writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubaddr); - writeb(0, &musbr->tar[MUSB_INTR_EP].rxhubport); - } -#endif - devspeed = musb_cfg.musb_speed; - } - - /* Write the saved toggle bit value */ - write_toggle(dev, ep, dir_out); - - if (!dir_out) { /* intrrupt-in transfer */ - /* Write the saved toggle bit value */ - write_toggle(dev, ep, dir_out); - writeb(interval, &musbr->rxinterval); - - /* Program the RxType register */ - type = (devspeed << MUSB_TYPE_SPEED_SHIFT) | - (MUSB_TYPE_PROTO_INTR << MUSB_TYPE_PROTO_SHIFT) | - (ep & MUSB_TYPE_REMOTE_END); - writeb(type, &musbr->rxtype); - - /* Write the maximum packet size to the RxMaxp register */ - writew(dev->epmaxpacketin[ep], &musbr->rxmaxp); - - while (txlen < len) { - nextlen = ((len-txlen) < dev->epmaxpacketin[ep]) ? - (len-txlen) : dev->epmaxpacketin[ep]; - - /* Set the ReqPkt bit */ - csr = readw(&musbr->rxcsr); - writew(csr | MUSB_RXCSR_H_REQPKT, &musbr->rxcsr); - - /* Wait until the RxPktRdy bit is set */ - if (wait_until_rxep_ready(dev, MUSB_INTR_EP) != 1) { - csr = readw(&musbr->rxcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); - csr &= ~MUSB_RXCSR_RXPKTRDY; - writew(csr, &musbr->rxcsr); - dev->act_len = txlen; - return 0; - } - - /* Read the data from the FIFO */ - read_fifo(MUSB_INTR_EP, nextlen, - (void *)(((u8 *)buffer) + txlen)); - - /* Clear the RxPktRdy bit */ - csr = readw(&musbr->rxcsr); - csr &= ~MUSB_RXCSR_RXPKTRDY; - writew(csr, &musbr->rxcsr); - txlen += nextlen; - } - - /* Keep a copy of the data toggle bit */ - csr = readw(&musbr->rxcsr); - usb_settoggle(dev, ep, dir_out, - (csr >> MUSB_S_RXCSR_H_DATATOGGLE) & 1); - } - - /* interrupt transfer is complete */ - dev->irq_status = 0; - dev->irq_act_len = len; - dev->irq_handle(dev); - dev->status = 0; - dev->act_len = len; - return 0; -} diff --git a/drivers/usb/musb/musb_hcd.h b/drivers/usb/musb/musb_hcd.h deleted file mode 100644 index a492e99ef9d..00000000000 --- a/drivers/usb/musb/musb_hcd.h +++ /dev/null @@ -1,93 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Mentor USB OTG Core host controller driver. - * - * Copyright (c) 2008 Texas Instruments - * - * Author: Thomas Abraham [email protected], Texas Instruments - */ - -#ifndef __MUSB_HCD_H__ -#define __MUSB_HCD_H__ - -#include "musb_core.h" -#ifdef CONFIG_USB_KEYBOARD -#include <stdio_dev.h> -extern unsigned char new[]; -#endif - -#define MUSB_TIMEOUT 100000 - -/* This defines the endpoint number used for control transfers */ -#define MUSB_CONTROL_EP 0 - -/* This defines the endpoint number used for bulk transfer */ -#ifndef MUSB_BULK_EP -# define MUSB_BULK_EP 1 -#endif - -/* This defines the endpoint number used for interrupt transfer */ -#define MUSB_INTR_EP 2 - -/* Determine the operating speed of MUSB core */ -#define musb_ishighspeed() \ - ((readb(&musbr->power) & MUSB_POWER_HSMODE) \ - >> MUSB_POWER_HSMODE_SHIFT) - -/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */ - -/* destination of request */ -#define RH_INTERFACE 0x01 -#define RH_ENDPOINT 0x02 -#define RH_OTHER 0x03 - -#define RH_CLASS 0x20 -#define RH_VENDOR 0x40 - -/* Requests: bRequest << 8 | bmRequestType */ -#define RH_GET_STATUS 0x0080 -#define RH_CLEAR_FEATURE 0x0100 -#define RH_SET_FEATURE 0x0300 -#define RH_SET_ADDRESS 0x0500 -#define RH_GET_DESCRIPTOR 0x0680 -#define RH_SET_DESCRIPTOR 0x0700 -#define RH_GET_CONFIGURATION 0x0880 -#define RH_SET_CONFIGURATION 0x0900 -#define RH_GET_STATE 0x0280 -#define RH_GET_INTERFACE 0x0A80 -#define RH_SET_INTERFACE 0x0B00 -#define RH_SYNC_FRAME 0x0C80 -/* Our Vendor Specific Request */ -#define RH_SET_EP 0x2000 - -/* Hub port features */ -#define RH_PORT_CONNECTION 0x00 -#define RH_PORT_ENABLE 0x01 -#define RH_PORT_SUSPEND 0x02 -#define RH_PORT_OVER_CURRENT 0x03 -#define RH_PORT_RESET 0x04 -#define RH_PORT_POWER 0x08 -#define RH_PORT_LOW_SPEED 0x09 - -#define RH_C_PORT_CONNECTION 0x10 -#define RH_C_PORT_ENABLE 0x11 -#define RH_C_PORT_SUSPEND 0x12 -#define RH_C_PORT_OVER_CURRENT 0x13 -#define RH_C_PORT_RESET 0x14 - -/* Hub features */ -#define RH_C_HUB_LOCAL_POWER 0x00 -#define RH_C_HUB_OVER_CURRENT 0x01 - -#define RH_DEVICE_REMOTE_WAKEUP 0x00 -#define RH_ENDPOINT_STALL 0x01 - -#define RH_ACK 0x01 -#define RH_REQ_ERR -1 -#define RH_NACK 0x00 - -/* extern functions */ -extern int musb_platform_init(void); -extern void musb_platform_deinit(void); - -#endif /* __MUSB_HCD_H__ */ diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c deleted file mode 100644 index 696855ee3a6..00000000000 --- a/drivers/usb/musb/musb_udc.c +++ /dev/null @@ -1,953 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2009 Wind River Systems, Inc. - * Tom Rix <[email protected]> - * - * This file is a rewrite of the usb device part of - * repository git.omapzoom.org/repo/u-boot.git, branch master, - * file cpu/omap3/fastboot.c - * - * This is the unique part of its copyright : - * - * ------------------------------------------------------------------------- - * - * (C) Copyright 2008 - 2009 - * Windriver, <www.windriver.com> - * Tom Rix <[email protected]> - * - * ------------------------------------------------------------------------- - * - * The details of connecting the device to the uboot usb device subsystem - * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git, - * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c - * - * This is the unique part of its copyright : - * - * ------------------------------------------------------------------------- - * - * (C) Copyright 2008 Texas Instruments Incorporated. - * - * Based on - * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c) - * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c) - * - * Author: Diego Dompe ([email protected]) - * Atin Malaviya ([email protected]) - * - * ------------------------------------------------------------------------- - */ - -#include <hang.h> -#include <serial.h> -#include <usbdevice.h> -#include <linux/delay.h> -#include <usb/udc.h> -#include "../gadget/ep0.h" -#include "musb_core.h" -#if defined(CONFIG_USB_OMAP3) -#include "omap3.h" -#elif defined(CONFIG_USB_AM35X) -#include "am35x.h" -#endif - -/* Define MUSB_DEBUG for debugging */ -/* #define MUSB_DEBUG */ -#include "musb_debug.h" - -#define MAX_ENDPOINT 15 - -#define GET_ENDPOINT(dev,ep) \ -(((struct usb_device_instance *)(dev))->bus->endpoint_array + ep) - -#define SET_EP0_STATE(s) \ -do { \ - if ((0 <= (s)) && (SET_ADDRESS >= (s))) { \ - if ((s) != ep0_state) { \ - if ((debug_setup) && (debug_level > 1)) \ - serial_printf("INFO : Changing state " \ - "from %s to %s in %s at " \ - "line %d\n", \ - ep0_state_strings[ep0_state],\ - ep0_state_strings[s], \ - __PRETTY_FUNCTION__, \ - __LINE__); \ - ep0_state = s; \ - } \ - } else { \ - if (debug_level > 0) \ - serial_printf("Error at %s %d with setting " \ - "state %d is invalid\n", \ - __PRETTY_FUNCTION__, __LINE__, s); \ - } \ -} while (0) - -/* static implies these initialized to 0 or NULL */ -static int debug_setup; -static int debug_level; -static struct musb_epinfo epinfo[MAX_ENDPOINT * 2 + 2]; -static enum ep0_state_enum { - IDLE = 0, - TX, - RX, - SET_ADDRESS -} ep0_state = IDLE; -static char *ep0_state_strings[4] = { - "IDLE", - "TX", - "RX", - "SET_ADDRESS", -}; - -static struct urb *ep0_urb; -struct usb_endpoint_instance *ep0_endpoint; -static struct usb_device_instance *udc_device; -static int enabled; - -static u16 pending_intrrx; - -#ifdef MUSB_DEBUG -static void musb_db_regs(void) -{ - u8 b; - u16 w; - - b = readb(&musbr->faddr); - serial_printf("\tfaddr 0x%2.2x\n", b); - - b = readb(&musbr->power); - musb_print_pwr(b); - - w = readw(&musbr->ep[0].ep0.csr0); - musb_print_csr0(w); - - b = readb(&musbr->devctl); - musb_print_devctl(b); - - b = readb(&musbr->ep[0].ep0.configdata); - musb_print_config(b); - - w = readw(&musbr->frame); - serial_printf("\tframe 0x%4.4x\n", w); - - b = readb(&musbr->index); - serial_printf("\tindex 0x%2.2x\n", b); - - w = readw(&musbr->ep[1].epN.rxmaxp); - musb_print_rxmaxp(w); - - w = readw(&musbr->ep[1].epN.rxcsr); - musb_print_rxcsr(w); - - w = readw(&musbr->ep[1].epN.txmaxp); - musb_print_txmaxp(w); - - w = readw(&musbr->ep[1].epN.txcsr); - musb_print_txcsr(w); -} -#else -#define musb_db_regs() -#endif /* DEBUG_MUSB */ - -static void musb_peri_softconnect(void) -{ - u8 power, devctl; - - /* Power off MUSB */ - power = readb(&musbr->power); - power &= ~MUSB_POWER_SOFTCONN; - writeb(power, &musbr->power); - - /* Read intr to clear */ - readb(&musbr->intrusb); - readw(&musbr->intrrx); - readw(&musbr->intrtx); - - udelay(1000 * 1000); /* 1 sec */ - - /* Power on MUSB */ - power = readb(&musbr->power); - power |= MUSB_POWER_SOFTCONN; - /* - * The usb device interface is usb 1.1 - * Disable 2.0 high speed by clearring the hsenable bit. - */ - power &= ~MUSB_POWER_HSENAB; - writeb(power, &musbr->power); - - /* Check if device is in b-peripheral mode */ - devctl = readb(&musbr->devctl); - if (!(devctl & MUSB_DEVCTL_BDEVICE) || - (devctl & MUSB_DEVCTL_HM)) { - serial_printf("ERROR : Unsupport USB mode\n"); - serial_printf("Check that mini-B USB cable is attached " - "to the device\n"); - } - - if (debug_setup && (debug_level > 1)) - musb_db_regs(); -} - -static void musb_peri_reset(void) -{ - if ((debug_setup) && (debug_level > 1)) - serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__); - - if (ep0_endpoint) - ep0_endpoint->endpoint_address = 0xff; - - /* Sync sw and hw addresses */ - writeb(udc_device->address, &musbr->faddr); - - SET_EP0_STATE(IDLE); -} - -static void musb_peri_resume(void) -{ - /* noop */ -} - -static void musb_peri_ep0_stall(void) -{ - u16 csr0; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - csr0 |= MUSB_CSR0_P_SENDSTALL; - writew(csr0, &musbr->ep[0].ep0.csr0); - if ((debug_setup) && (debug_level > 1)) - serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__); -} - -static void musb_peri_ep0_ack_req(void) -{ - u16 csr0; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - csr0 |= MUSB_CSR0_P_SVDRXPKTRDY; - writew(csr0, &musbr->ep[0].ep0.csr0); -} - -static void musb_ep0_tx_ready(void) -{ - u16 csr0; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - csr0 |= MUSB_CSR0_TXPKTRDY; - writew(csr0, &musbr->ep[0].ep0.csr0); -} - -static void musb_ep0_tx_ready_and_last(void) -{ - u16 csr0; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND); - writew(csr0, &musbr->ep[0].ep0.csr0); -} - -static void musb_peri_ep0_last(void) -{ - u16 csr0; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - csr0 |= MUSB_CSR0_P_DATAEND; - writew(csr0, &musbr->ep[0].ep0.csr0); -} - -static void musb_peri_ep0_set_address(void) -{ - u8 faddr; - writeb(udc_device->address, &musbr->faddr); - - /* Verify */ - faddr = readb(&musbr->faddr); - if (udc_device->address == faddr) { - SET_EP0_STATE(IDLE); - usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0); - if ((debug_setup) && (debug_level > 1)) - serial_printf("INFO : %s Address set to %d\n", - __PRETTY_FUNCTION__, udc_device->address); - } else { - if (debug_level > 0) - serial_printf("ERROR : %s Address mismatch " - "sw %d vs hw %d\n", - __PRETTY_FUNCTION__, - udc_device->address, faddr); - } -} - -static void musb_peri_rx_ack(unsigned int ep) -{ - u16 peri_rxcsr; - - peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr); - peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY; - writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr); -} - -static void musb_peri_tx_ready(unsigned int ep) -{ - u16 peri_txcsr; - - peri_txcsr = readw(&musbr->ep[ep].epN.txcsr); - peri_txcsr |= MUSB_TXCSR_TXPKTRDY; - writew(peri_txcsr, &musbr->ep[ep].epN.txcsr); -} - -static void musb_peri_ep0_zero_data_request(int err) -{ - musb_peri_ep0_ack_req(); - - if (err) { - musb_peri_ep0_stall(); - SET_EP0_STATE(IDLE); - } else { - - musb_peri_ep0_last(); - - /* USBD state */ - switch (ep0_urb->device_request.bRequest) { - case USB_REQ_SET_ADDRESS: - if ((debug_setup) && (debug_level > 1)) - serial_printf("INFO : %s received set " - "address\n", __PRETTY_FUNCTION__); - break; - - case USB_REQ_SET_CONFIGURATION: - if ((debug_setup) && (debug_level > 1)) - serial_printf("INFO : %s Configured\n", - __PRETTY_FUNCTION__); - usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); - break; - } - - /* EP0 state */ - if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) { - SET_EP0_STATE(SET_ADDRESS); - } else { - SET_EP0_STATE(IDLE); - } - } -} - -static void musb_peri_ep0_rx_data_request(void) -{ - /* - * This is the completion of the data OUT / RX - * - * Host is sending data to ep0 that is not - * part of setup. This comes from the cdc_recv_setup - * op that is device specific. - * - */ - musb_peri_ep0_ack_req(); - - ep0_endpoint->rcv_urb = ep0_urb; - ep0_urb->actual_length = 0; - SET_EP0_STATE(RX); -} - -static void musb_peri_ep0_tx_data_request(int err) -{ - if (err) { - musb_peri_ep0_stall(); - SET_EP0_STATE(IDLE); - } else { - musb_peri_ep0_ack_req(); - - ep0_endpoint->tx_urb = ep0_urb; - ep0_endpoint->sent = 0; - SET_EP0_STATE(TX); - } -} - -static void musb_peri_ep0_idle(void) -{ - u16 count0; - int err; - u16 csr0; - - /* - * Verify addresses - * A lot of confusion can be caused if the address - * in software, udc layer, does not agree with the - * hardware. Since the setting of the hardware address - * must be set after the set address request, the - * usb state machine is out of sync for a few frame. - * It is a good idea to run this check when changes - * are made to the state machine. - */ - if ((debug_level > 0) && - (ep0_state != SET_ADDRESS)) { - u8 faddr; - - faddr = readb(&musbr->faddr); - if (udc_device->address != faddr) { - serial_printf("ERROR : %s addresses do not" - "match sw %d vs hw %d\n", - __PRETTY_FUNCTION__, - udc_device->address, faddr); - udelay(1000 * 1000); - hang(); - } - } - - csr0 = readw(&musbr->ep[0].ep0.csr0); - - if (!(MUSB_CSR0_RXPKTRDY & csr0)) - goto end; - - count0 = readw(&musbr->ep[0].ep0.count0); - if (count0 == 0) - goto end; - - if (count0 != 8) { - if ((debug_setup) && (debug_level > 1)) - serial_printf("WARN : %s SETUP incorrect size %d\n", - __PRETTY_FUNCTION__, count0); - musb_peri_ep0_stall(); - goto end; - } - - read_fifo(0, count0, &ep0_urb->device_request); - - if (debug_level > 2) - print_usb_device_request(&ep0_urb->device_request); - - if (ep0_urb->device_request.wLength == 0) { - err = ep0_recv_setup(ep0_urb); - - /* Zero data request */ - musb_peri_ep0_zero_data_request(err); - } else { - /* Is data coming or going ? */ - u8 reqType = ep0_urb->device_request.bmRequestType; - - if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) { - err = ep0_recv_setup(ep0_urb); - /* Device to host */ - musb_peri_ep0_tx_data_request(err); - } else { - /* - * Host to device - * - * The RX routine will call ep0_recv_setup - * when the data packet has arrived. - */ - musb_peri_ep0_rx_data_request(); - } - } - -end: - return; -} - -static void musb_peri_ep0_rx(void) -{ - /* - * This is the completion of the data OUT / RX - * - * Host is sending data to ep0 that is not - * part of setup. This comes from the cdc_recv_setup - * op that is device specific. - * - * Pass the data back to driver ep0_recv_setup which - * should give the cdc_recv_setup the chance to handle - * the rx - */ - u16 csr0; - u16 count0; - - if (debug_level > 3) { - if (0 != ep0_urb->actual_length) { - serial_printf("%s finished ? %d of %d\n", - __PRETTY_FUNCTION__, - ep0_urb->actual_length, - ep0_urb->device_request.wLength); - } - } - - if (ep0_urb->device_request.wLength == ep0_urb->actual_length) { - musb_peri_ep0_last(); - SET_EP0_STATE(IDLE); - ep0_recv_setup(ep0_urb); - return; - } - - csr0 = readw(&musbr->ep[0].ep0.csr0); - if (!(MUSB_CSR0_RXPKTRDY & csr0)) - return; - - count0 = readw(&musbr->ep[0].ep0.count0); - - if (count0) { - struct usb_endpoint_instance *endpoint; - u32 length; - u8 *data; - - endpoint = ep0_endpoint; - if (endpoint && endpoint->rcv_urb) { - struct urb *urb = endpoint->rcv_urb; - unsigned int remaining_space = urb->buffer_length - - urb->actual_length; - - if (remaining_space) { - int urb_bad = 0; /* urb is good */ - - if (count0 > remaining_space) - length = remaining_space; - else - length = count0; - - data = (u8 *) urb->buffer_data; - data += urb->actual_length; - - /* The common musb fifo reader */ - read_fifo(0, length, data); - - musb_peri_ep0_ack_req(); - - /* - * urb's actual_length is updated in - * usbd_rcv_complete - */ - usbd_rcv_complete(endpoint, length, urb_bad); - - } else { - if (debug_level > 0) - serial_printf("ERROR : %s no space in " - "rcv buffer\n", - __PRETTY_FUNCTION__); - } - } else { - if (debug_level > 0) - serial_printf("ERROR : %s problem with " - "endpoint\n", - __PRETTY_FUNCTION__); - } - } else { - if (debug_level > 0) - serial_printf("ERROR : %s with nothing to do\n", - __PRETTY_FUNCTION__); - } -} - -static void musb_peri_ep0_tx(void) -{ - u16 csr0; - int transfer_size = 0; - unsigned int p, pm; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - - /* Check for pending tx */ - if (csr0 & MUSB_CSR0_TXPKTRDY) - goto end; - - /* Check if this is the last packet sent */ - if (ep0_endpoint->sent >= ep0_urb->actual_length) { - SET_EP0_STATE(IDLE); - goto end; - } - - transfer_size = ep0_urb->actual_length - ep0_endpoint->sent; - /* Is the transfer size negative ? */ - if (transfer_size <= 0) { - if (debug_level > 0) - serial_printf("ERROR : %s problem with the" - " transfer size %d\n", - __PRETTY_FUNCTION__, - transfer_size); - SET_EP0_STATE(IDLE); - goto end; - } - - /* Truncate large transfers to the fifo size */ - if (transfer_size > ep0_endpoint->tx_packetSize) - transfer_size = ep0_endpoint->tx_packetSize; - - write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]); - ep0_endpoint->sent += transfer_size; - - /* Done or more to send ? */ - if (ep0_endpoint->sent >= ep0_urb->actual_length) - musb_ep0_tx_ready_and_last(); - else - musb_ep0_tx_ready(); - - /* Wait a bit */ - pm = 10; - for (p = 0; p < pm; p++) { - csr0 = readw(&musbr->ep[0].ep0.csr0); - if (!(csr0 & MUSB_CSR0_TXPKTRDY)) - break; - - /* Double the delay. */ - udelay(1 << pm); - } - - if ((ep0_endpoint->sent >= ep0_urb->actual_length) && (p < pm)) - SET_EP0_STATE(IDLE); - -end: - return; -} - -static void musb_peri_ep0(void) -{ - u16 csr0; - - if (SET_ADDRESS == ep0_state) - return; - - csr0 = readw(&musbr->ep[0].ep0.csr0); - - /* Error conditions */ - if (MUSB_CSR0_P_SENTSTALL & csr0) { - csr0 &= ~MUSB_CSR0_P_SENTSTALL; - writew(csr0, &musbr->ep[0].ep0.csr0); - SET_EP0_STATE(IDLE); - } - if (MUSB_CSR0_P_SETUPEND & csr0) { - csr0 |= MUSB_CSR0_P_SVDSETUPEND; - writew(csr0, &musbr->ep[0].ep0.csr0); - SET_EP0_STATE(IDLE); - if ((debug_setup) && (debug_level > 1)) - serial_printf("WARN: %s SETUPEND\n", - __PRETTY_FUNCTION__); - } - - /* Normal states */ - if (IDLE == ep0_state) - musb_peri_ep0_idle(); - - if (TX == ep0_state) - musb_peri_ep0_tx(); - - if (RX == ep0_state) - musb_peri_ep0_rx(); -} - -static void musb_peri_rx_ep(unsigned int ep) -{ - u16 peri_rxcount; - u16 peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr); - - if (!(peri_rxcsr & MUSB_RXCSR_RXPKTRDY)) { - if (debug_level > 0) - serial_printf("ERROR : %s %d without MUSB_RXCSR_RXPKTRDY set\n", - __PRETTY_FUNCTION__, ep); - return; - } - - peri_rxcount = readw(&musbr->ep[ep].epN.rxcount); - if (peri_rxcount) { - struct usb_endpoint_instance *endpoint; - u32 length; - u8 *data; - - endpoint = GET_ENDPOINT(udc_device, ep); - if (endpoint && endpoint->rcv_urb) { - struct urb *urb = endpoint->rcv_urb; - unsigned int remaining_space = urb->buffer_length - - urb->actual_length; - - if (remaining_space) { - int urb_bad = 0; /* urb is good */ - - if (peri_rxcount > remaining_space) - length = remaining_space; - else - length = peri_rxcount; - - data = (u8 *) urb->buffer_data; - data += urb->actual_length; - - /* The common musb fifo reader */ - read_fifo(ep, length, data); - - if (length == peri_rxcount) - musb_peri_rx_ack(ep); - else - pending_intrrx |= (1 << ep); - - /* - * urb's actual_length is updated in - * usbd_rcv_complete - */ - usbd_rcv_complete(endpoint, length, urb_bad); - - } else { - if (debug_level > 0) - serial_printf("ERROR : %s %d no space " - "in rcv buffer\n", - __PRETTY_FUNCTION__, ep); - - pending_intrrx |= (1 << ep); - } - } else { - if (debug_level > 0) - serial_printf("ERROR : %s %d problem with " - "endpoint\n", - __PRETTY_FUNCTION__, ep); - - pending_intrrx |= (1 << ep); - } - - } else { - if (debug_level > 0) - serial_printf("ERROR : %s %d with nothing to do\n", - __PRETTY_FUNCTION__, ep); - - musb_peri_rx_ack(ep); - } -} - -static void musb_peri_rx(u16 intr) -{ - unsigned int ep; - - /* First bit is reserved and does not indicate interrupt for EP0 */ - - for (ep = 1; ep < 16; ep++) { - if ((1 << ep) & intr) - musb_peri_rx_ep(ep); - } -} - -static void musb_peri_tx(u16 intr) -{ - unsigned int ep; - - /* Check for EP0: first bit indicates interrupt for both RX and TX */ - if (0x01 & intr) - musb_peri_ep0(); - - for (ep = 1; ep < 16; ep++) { - if ((1 << ep) & intr) - udc_endpoint_write(GET_ENDPOINT(udc_device, ep)); - } -} - -void udc_irq(void) -{ - /* This is a high freq called function */ - if (enabled) { - u8 intrusb; - - intrusb = readb(&musbr->intrusb); - - /* - * See drivers/usb/gadget/mpc8xx_udc.c for - * state diagram going from detached through - * configuration. - */ - if (MUSB_INTR_RESUME & intrusb) { - usbd_device_event_irq(udc_device, - DEVICE_BUS_ACTIVITY, 0); - musb_peri_resume(); - } - - if (MUSB_INTR_RESET & intrusb) { - usbd_device_event_irq(udc_device, DEVICE_RESET, 0); - musb_peri_reset(); - } - - if (MUSB_INTR_DISCONNECT & intrusb) { - /* cable unplugged from hub/host */ - usbd_device_event_irq(udc_device, DEVICE_RESET, 0); - musb_peri_reset(); - usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); - } - - if (MUSB_INTR_SOF & intrusb) { - usbd_device_event_irq(udc_device, - DEVICE_BUS_ACTIVITY, 0); - musb_peri_resume(); - } - - if (MUSB_INTR_SUSPEND & intrusb) { - usbd_device_event_irq(udc_device, - DEVICE_BUS_INACTIVE, 0); - } - - if (ep0_state != SET_ADDRESS) { - u16 intrrx, intrtx; - - intrrx = readw(&musbr->intrrx); - intrtx = readw(&musbr->intrtx); - - intrrx |= pending_intrrx; - pending_intrrx = 0; - - if (intrrx) - musb_peri_rx(intrrx); - - if (intrtx) - musb_peri_tx(intrtx); - } else { - if (readw(&musbr->intrtx) & 0x1) { - u8 faddr; - faddr = readb(&musbr->faddr); - /* - * Setting of the address can fail. - * Normally it succeeds the second time. - */ - if (udc_device->address != faddr) - musb_peri_ep0_set_address(); - } - } - } -} - -void udc_set_nak(int ep_num) -{ - /* noop */ -} - -void udc_unset_nak(int ep_num) -{ - /* noop */ -} - -int udc_endpoint_write(struct usb_endpoint_instance *endpoint) -{ - int ret = 0; - - /* Transmit only if the hardware is available */ - if (endpoint->tx_urb && endpoint->state == 0) { - unsigned int ep = endpoint->endpoint_address & - USB_ENDPOINT_NUMBER_MASK; - - u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr); - - /* Error conditions */ - if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) { - peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN; - writew(peri_txcsr, &musbr->ep[ep].epN.txcsr); - } - - if (debug_level > 1) - musb_print_txcsr(peri_txcsr); - - /* Check if a packet is waiting to be sent */ - if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) { - u32 length; - u8 *data; - struct urb *urb = endpoint->tx_urb; - unsigned int remaining_packet = urb->actual_length - - endpoint->sent; - - if (endpoint->tx_packetSize < remaining_packet) - length = endpoint->tx_packetSize; - else - length = remaining_packet; - - data = (u8 *) urb->buffer; - data += endpoint->sent; - - /* common musb fifo function */ - write_fifo(ep, length, data); - - musb_peri_tx_ready(ep); - - endpoint->last = length; - /* usbd_tx_complete will take care of updating 'sent' */ - usbd_tx_complete(endpoint); - } - } else { - if (debug_level > 0) - serial_printf("ERROR : %s Problem with urb %p " - "or ep state %d\n", - __PRETTY_FUNCTION__, - endpoint->tx_urb, endpoint->state); - } - - return ret; -} - -void udc_setup_ep(struct usb_device_instance *device, unsigned int id, - struct usb_endpoint_instance *endpoint) -{ - if (0 == id) { - /* EP0 */ - ep0_endpoint = endpoint; - ep0_endpoint->endpoint_address = 0xff; - ep0_urb = usbd_alloc_urb(device, endpoint); - } else if (MAX_ENDPOINT >= id) { - epinfo[(id * 2) + 0].epsize = endpoint->rcv_packetSize; - epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize; - musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo)); - } else { - if (debug_level > 0) - serial_printf("ERROR : %s endpoint request %d " - "exceeds maximum %d\n", - __PRETTY_FUNCTION__, id, MAX_ENDPOINT); - } -} - -void udc_connect(void) -{ - /* noop */ -} - -void udc_disconnect(void) -{ - /* noop */ -} - -void udc_enable(struct usb_device_instance *device) -{ - /* Save the device structure pointer */ - udc_device = device; - - enabled = 1; -} - -void udc_disable(void) -{ - enabled = 0; -} - -void udc_startup_events(struct usb_device_instance *device) -{ - /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ - usbd_device_event_irq(device, DEVICE_INIT, 0); - - /* - * The DEVICE_CREATE event puts the USB device in the state - * STATE_ATTACHED. - */ - usbd_device_event_irq(device, DEVICE_CREATE, 0); - - /* Resets the address to 0 */ - usbd_device_event_irq(device, DEVICE_RESET, 0); - - udc_enable(device); -} - -int udc_init(void) -{ - int ret; - int ep_loop; - - ret = musb_platform_init(); - if (ret < 0) - goto end; - - /* Configure all the endpoint FIFO's and start usb controller */ - musbr = musb_cfg.regs; - - /* Initialize the endpoints */ - for (ep_loop = 0; ep_loop <= MAX_ENDPOINT * 2; ep_loop++) { - epinfo[ep_loop].epnum = (ep_loop / 2) + 1; - epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */ - epinfo[ep_loop].epsize = 0; - } - - musb_peri_softconnect(); - - ret = 0; -end: - - return ret; -} diff --git a/drivers/usb/musb/omap3.c b/drivers/usb/musb/omap3.c deleted file mode 100644 index e5238bc02f8..00000000000 --- a/drivers/usb/musb/omap3.c +++ /dev/null @@ -1,129 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (c) 2009 Wind River Systems, Inc. - * Tom Rix <[email protected]> - * - * This is file is based on - * repository git.gitorious.org/u-boot-omap3/mainline.git, - * branch omap3-dev-usb, file drivers/usb/host/omap3530_usb.c - * - * This is the unique part of its copyright : - * - * ------------------------------------------------------------------------ - * - * Copyright (c) 2009 Texas Instruments - * - * ------------------------------------------------------------------------ - */ - -#include <serial.h> -#include <asm/omap_common.h> -#include <twl4030.h> -#include "omap3.h" - -static int platform_needs_initialization = 1; - -struct musb_config musb_cfg = { - .regs = (struct musb_regs *)MENTOR_USB0_BASE, - .timeout = OMAP3_USB_TIMEOUT, - .musb_speed = 0, -}; - -/* - * OMAP3 USB OTG registers. - */ -struct omap3_otg_regs { - u32 revision; - u32 sysconfig; - u32 sysstatus; - u32 interfsel; - u32 simenable; - u32 forcestdby; -}; - -static struct omap3_otg_regs *otg; - -#define OMAP3_OTG_SYSCONFIG_SMART_STANDBY_MODE 0x2000 -#define OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE 0x1000 -#define OMAP3_OTG_SYSCONFIG_SMART_IDLE_MODE 0x0010 -#define OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE 0x0008 -#define OMAP3_OTG_SYSCONFIG_ENABLEWAKEUP 0x0004 -#define OMAP3_OTG_SYSCONFIG_SOFTRESET 0x0002 -#define OMAP3_OTG_SYSCONFIG_AUTOIDLE 0x0001 - -#define OMAP3_OTG_SYSSTATUS_RESETDONE 0x0001 - -#define OMAP3_OTG_INTERFSEL_OMAP 0x0001 - -#define OMAP3_OTG_FORCESTDBY_STANDBY 0x0001 - -#ifdef DEBUG_MUSB_OMAP3 -static void musb_db_otg_regs(void) -{ - u32 l; - l = readl(&otg->revision); - serial_printf("OTG_REVISION 0x%x\n", l); - l = readl(&otg->sysconfig); - serial_printf("OTG_SYSCONFIG 0x%x\n", l); - l = readl(&otg->sysstatus); - serial_printf("OTG_SYSSTATUS 0x%x\n", l); - l = readl(&otg->interfsel); - serial_printf("OTG_INTERFSEL 0x%x\n", l); - l = readl(&otg->forcestdby); - serial_printf("OTG_FORCESTDBY 0x%x\n", l); -} -#endif - -int musb_platform_init(void) -{ - int ret = -1; - - if (platform_needs_initialization) { - u32 stdby; - - /* - * OMAP3EVM uses ISP1504 phy and so - * twl4030 related init is not required. - */ -#ifdef CONFIG_TWL4030_USB - if (twl4030_usb_ulpi_init()) { - serial_printf("ERROR: %s Could not initialize PHY\n", - __PRETTY_FUNCTION__); - goto end; - } -#endif - - otg = (struct omap3_otg_regs *)OMAP3_OTG_BASE; - - /* Set OTG to always be on */ - writel(OMAP3_OTG_SYSCONFIG_NO_STANDBY_MODE | - OMAP3_OTG_SYSCONFIG_NO_IDLE_MODE, &otg->sysconfig); - - /* Set the interface */ - writel(OMAP3_OTG_INTERFSEL_OMAP, &otg->interfsel); - - /* Clear force standby */ - stdby = readl(&otg->forcestdby); - stdby &= ~OMAP3_OTG_FORCESTDBY_STANDBY; - writel(stdby, &otg->forcestdby); - -#ifdef CONFIG_TARGET_OMAP3_EVM - musb_cfg.extvbus = omap3_evm_need_extvbus(); -#endif - - platform_needs_initialization = 0; - } - - ret = platform_needs_initialization; - -#ifdef CONFIG_TWL4030_USB -end: -#endif - return ret; - -} - -void musb_platform_deinit(void) -{ - /* noop */ -} diff --git a/drivers/usb/musb/omap3.h b/drivers/usb/musb/omap3.h deleted file mode 100644 index 78fdb2959bb..00000000000 --- a/drivers/usb/musb/omap3.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (c) 2009 Wind River Systems, Inc. - * Tom Rix <[email protected]> - * - * This file is based on the file drivers/usb/musb/davinci.h - * - * This is the unique part of its copyright: - * - * -------------------------------------------------------------------- - * - * Copyright (c) 2008 Texas Instruments - * Author: Thomas Abraham [email protected], Texas Instruments - * - * -------------------------------------------------------------------- - */ -#ifndef _MUSB_OMAP3_H_ -#define _MUSB_OMAP3_H_ - -#include <asm/arch/cpu.h> -#include "musb_core.h" - -/* Base address of MUSB registers */ -#define MENTOR_USB0_BASE MUSB_BASE - -/* Base address of OTG registers */ -#define OMAP3_OTG_BASE (MENTOR_USB0_BASE + 0x400) - -/* Timeout for USB module */ -#define OMAP3_USB_TIMEOUT 0x3FFFFFF - -int musb_platform_init(void); - -#ifdef CONFIG_TARGET_OMAP3_EVM -extern u8 omap3_evm_need_extvbus(void); -#endif - -#endif /* _MUSB_OMAP3_H */ diff --git a/drivers/video/simple_panel.c b/drivers/video/simple_panel.c index b6c5b058b2e..0f23df701bc 100644 --- a/drivers/video/simple_panel.c +++ b/drivers/video/simple_panel.c @@ -191,6 +191,7 @@ static const struct mipi_dsi_panel_plat panasonic_vvx10f004b00 = { static const struct udevice_id simple_panel_ids[] = { { .compatible = "simple-panel" }, + { .compatible = "panel-lvds" }, { .compatible = "auo,b133xtn01" }, { .compatible = "auo,b116xw03" }, { .compatible = "auo,b133htn01" }, diff --git a/drivers/video/stm32/Kconfig b/drivers/video/stm32/Kconfig index c354c402c28..4cb8a841caf 100644 --- a/drivers/video/stm32/Kconfig +++ b/drivers/video/stm32/Kconfig @@ -23,6 +23,15 @@ config VIDEO_STM32_DSI This option enables support DSI internal bridge which can be used on devices which have DSI devices connected. +config VIDEO_STM32_LVDS + bool "Enable STM32 LVDS video support" + depends on VIDEO_STM32 + select VIDEO_BRIDGE + select VIDEO_DW_MIPI_DSI + help + This enables Low Voltage Differential Signaling (LVDS) display + support. + config VIDEO_STM32_MAX_XRES int "Maximum horizontal resolution (for memory allocation purposes)" depends on VIDEO_STM32 diff --git a/drivers/video/stm32/Makefile b/drivers/video/stm32/Makefile index f8b42d1a4d1..059d9000c1d 100644 --- a/drivers/video/stm32/Makefile +++ b/drivers/video/stm32/Makefile @@ -7,3 +7,4 @@ obj-${CONFIG_VIDEO_STM32} = stm32_ltdc.o obj-${CONFIG_VIDEO_STM32_DSI} += stm32_dsi.o +obj-${CONFIG_VIDEO_STM32_LVDS} += stm32_lvds.o diff --git a/drivers/video/stm32/stm32_ltdc.c b/drivers/video/stm32/stm32_ltdc.c index 0a062c8939d..834bfb625d2 100644 --- a/drivers/video/stm32/stm32_ltdc.c +++ b/drivers/video/stm32/stm32_ltdc.c @@ -17,6 +17,7 @@ #include <video_bridge.h> #include <asm/io.h> #include <dm/device-internal.h> +#include <dm/uclass-internal.h> #include <dm/device_compat.h> #include <linux/bitops.h> #include <linux/printk.h> @@ -262,6 +263,7 @@ static const u32 layer_regs_a2[] = { #define HWVER_10300 0x010300 #define HWVER_20101 0x020101 #define HWVER_40100 0x040100 +#define HWVER_40101 0x040101 enum stm32_ltdc_pix_fmt { PF_ARGB8888 = 0, /* ARGB [32 bits] */ @@ -494,6 +496,101 @@ static void stm32_ltdc_set_layer1(struct stm32_ltdc_priv *priv, ulong fb_addr) setbits_le32(priv->regs + LTDC_L1CR, LXCR_LEN); } +static int stm32_ltdc_get_remote_device(struct udevice *dev, ofnode ep_node, + enum uclass_id id, struct udevice **remote_dev) +{ + u32 remote_phandle; + ofnode remote; + int ret = 0; + + ret = ofnode_read_u32(ep_node, "remote-endpoint", &remote_phandle); + if (ret) { + dev_err(dev, "%s(%s): Could not find remote-endpoint property\n", + __func__, dev_read_name(dev)); + return ret; + } + + remote = ofnode_get_by_phandle(remote_phandle); + if (!ofnode_valid(remote)) + return -EINVAL; + + while (ofnode_valid(remote)) { + remote = ofnode_get_parent(remote); + if (!ofnode_valid(remote)) { + dev_dbg(dev, "%s(%s): no uclass_id %d for remote-endpoint\n", + __func__, dev_read_name(dev), id); + continue; + } + + ret = uclass_find_device_by_ofnode(id, remote, remote_dev); + if (*remote_dev && !ret) { + ret = uclass_get_device_by_ofnode(id, remote, remote_dev); + if (ret) + dev_dbg(dev, "%s(%s): failed to get remote device %s\n", + __func__, dev_read_name(dev), dev_read_name(*remote_dev)); + break; + } + }; + + return ret; +} + +static int stm32_ltdc_get_panel(struct udevice *dev, struct udevice **panel) +{ + ofnode ep_node, node, ports; + int ret = 0; + + if (!dev) + return -EINVAL; + + ports = ofnode_find_subnode(dev_ofnode(dev), "ports"); + if (!ofnode_valid(ports)) { + dev_err(dev, "Remote bridge subnode\n"); + return ret; + } + + for (node = ofnode_first_subnode(ports); + ofnode_valid(node); + node = dev_read_next_subnode(node)) { + ep_node = ofnode_first_subnode(node); + if (!ofnode_valid(ep_node)) + continue; + + ret = stm32_ltdc_get_remote_device(dev, ep_node, UCLASS_PANEL, panel); + } + + /* Sanity check, we can get out of the loop without having a clean ofnode */ + if (!(*panel)) + ret = -EINVAL; + else + if (!ofnode_valid(dev_ofnode(*panel))) + ret = -EINVAL; + + return ret; +} + +static int stm32_ltdc_display_init(struct udevice *dev, ofnode *ep_node, + struct udevice **panel, struct udevice **bridge) +{ + int ret; + + if (*panel) + return -EINVAL; + + if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) { + ret = stm32_ltdc_get_remote_device(dev, *ep_node, UCLASS_VIDEO_BRIDGE, bridge); + if (ret) + return ret; + + ret = stm32_ltdc_get_panel(*bridge, panel); + } else { + /* no bridge, search a panel from display controller node */ + ret = stm32_ltdc_get_remote_device(dev, *ep_node, UCLASS_PANEL, panel); + } + + return ret; +} + #if IS_ENABLED(CONFIG_TARGET_STM32F469_DISCOVERY) static int stm32_ltdc_alloc_fb(struct udevice *dev) { @@ -529,8 +626,9 @@ static int stm32_ltdc_probe(struct udevice *dev) struct udevice *bridge = NULL; struct udevice *panel = NULL; struct display_timing timings; - struct clk pclk; + struct clk pclk, bclk; struct reset_ctl rst; + ofnode node, port; ulong rate; int ret; @@ -540,7 +638,21 @@ static int stm32_ltdc_probe(struct udevice *dev) return -EINVAL; } - ret = clk_get_by_index(dev, 0, &pclk); + ret = clk_get_by_name(dev, "bus", &bclk); + if (ret) { + if (ret != -ENODATA) { + dev_err(dev, "bus clock get error %d\n", ret); + return ret; + } + } else { + ret = clk_enable(&bclk); + if (ret) { + dev_err(dev, "bus clock enable error %d\n", ret); + return ret; + } + } + + ret = clk_get_by_name(dev, "lcd", &pclk); if (ret) { dev_err(dev, "peripheral clock get error %d\n", ret); return ret; @@ -553,7 +665,7 @@ static int stm32_ltdc_probe(struct udevice *dev) } priv->hw_version = readl(priv->regs + LTDC_IDR); - debug("%s: LTDC hardware 0x%x\n", __func__, priv->hw_version); + dev_dbg(dev, "%s: LTDC hardware 0x%x\n", __func__, priv->hw_version); switch (priv->hw_version) { case HWVER_10200: @@ -566,6 +678,7 @@ static int stm32_ltdc_probe(struct udevice *dev) priv->pix_fmt_hw = pix_fmt_a1; break; case HWVER_40100: + case HWVER_40101: priv->layer_regs = layer_regs_a2; priv->pix_fmt_hw = pix_fmt_a2; break; @@ -573,13 +686,35 @@ static int stm32_ltdc_probe(struct udevice *dev) return -ENODEV; } - ret = uclass_first_device_err(UCLASS_PANEL, &panel); - if (ret) { - if (ret != -ENODEV) - dev_err(dev, "panel device error %d\n", ret); - return ret; + /* + * Try all the ports until one working. + * + * This is done in two times. First is checks for the + * UCLASS_VIDEO_BRIDGE available, and then for this bridge + * it scans for a UCLASS_PANEL. + */ + + port = dev_read_subnode(dev, "port"); + if (!ofnode_valid(port)) { + dev_err(dev, "%s(%s): 'port' subnode not found\n", + __func__, dev_read_name(dev)); + return -EINVAL; } + for (node = ofnode_first_subnode(port); + ofnode_valid(node); + node = dev_read_next_subnode(node)) { + ret = stm32_ltdc_display_init(dev, &node, &panel, &bridge); + if (ret) + dev_dbg(dev, "Device failed ret=%d\n", ret); + else + break; + } + + /* Sanity check */ + if (ret) + return ret; + ret = panel_get_display_timing(panel, &timings); if (ret) { ret = ofnode_decode_display_timing(dev_ofnode(panel), @@ -608,11 +743,6 @@ static int stm32_ltdc_probe(struct udevice *dev) reset_deassert(&rst); if (IS_ENABLED(CONFIG_VIDEO_BRIDGE)) { - ret = uclass_get_device(UCLASS_VIDEO_BRIDGE, 0, &bridge); - if (ret) - dev_dbg(dev, - "No video bridge, or no backlight on bridge\n"); - if (bridge) { ret = video_bridge_attach(bridge); if (ret) { @@ -688,6 +818,8 @@ static int stm32_ltdc_bind(struct udevice *dev) static const struct udevice_id stm32_ltdc_ids[] = { { .compatible = "st,stm32-ltdc" }, + { .compatible = "st,stm32mp251-ltdc" }, + { .compatible = "st,stm32mp255-ltdc" }, { } }; diff --git a/drivers/video/stm32/stm32_lvds.c b/drivers/video/stm32/stm32_lvds.c new file mode 100644 index 00000000000..bf1393c9e87 --- /dev/null +++ b/drivers/video/stm32/stm32_lvds.c @@ -0,0 +1,693 @@ +// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause +/* + * Copyright (C) 2025 STMicroelectronics - All Rights Reserved + * Author(s): RaphaĆ«l Gallais-Pou <[email protected]> for STMicroelectronics. + * + * This Low Voltage Differential Signal controller driver is based on the Linux Kernel driver from + * drivers/gpu/drm/stm/ltdc.c + */ + +#define LOG_CATEGORY UCLASS_VIDEO_BRIDGE + +#include <clk.h> +#include <dm.h> +#include <log.h> +#include <media_bus_format.h> +#include <panel.h> +#include <reset.h> +#include <video.h> +#include <video_bridge.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <dm/ofnode.h> +#include <linux/iopoll.h> + +/* LVDS Host registers */ +#define LVDS_CR 0x0000 /* configuration register */ +#define LVDS_DMLCR0 0x0004 /* data mapping lsb configuration register 0 */ +#define LVDS_DMMCR0 0x0008 /* data mapping msb configuration register 0 */ +#define LVDS_DMLCR1 0x000C /* data mapping lsb configuration register 1 */ +#define LVDS_DMMCR1 0x0010 /* data mapping msb configuration register 1 */ +#define LVDS_DMLCR2 0x0014 /* data mapping lsb configuration register 2 */ +#define LVDS_DMMCR2 0x0018 /* data mapping msb configuration register 2 */ +#define LVDS_DMLCR3 0x001C /* data mapping lsb configuration register 3 */ +#define LVDS_DMMCR3 0x0020 /* data mapping msb configuration register 3 */ +#define LVDS_DMLCR4 0x0024 /* data mapping lsb configuration register 4 */ +#define LVDS_DMMCR4 0x0028 /* data mapping msb configuration register 4 */ +#define LVDS_DMLCR(id) (LVDS_DMLCR0 + 8U * (id)) +#define LVDS_DMMCR(id) (LVDS_DMMCR0 + 8U * (id)) +#define LVDS_CDL1CR 0x002C /* channel distrib link 1 configuration register */ +#define LVDS_CDL2CR 0x0030 /* channel distrib link 2 configuration register */ + +#define CDL1CR_DEFAULT 0x4321 +#define CDL2CR_DEFAULT 0x59876 + +/* LVDS Host registers */ +#define LVDS_PHY_MASTER 0x0 +#define LVDS_PHY_SLAVE 0x100 + +/* phy parameter can only be one of those two above */ +#define LVDS_PXGCR(phy) ((phy) + 0x1000) /* Global Control Register */ +#define LVDS_PXCMCR1(phy) ((phy) + 0x100C) /* Current Mode Control Register 1 */ +#define LVDS_PXCMCR2(phy) ((phy) + 0x1010) /* Current Mode Control Register 2 */ +#define LVDS_PXSCR(phy) ((phy) + 0x1020) /* Serial Control Register */ +#define LVDS_PXBCR1(phy) ((phy) + 0x102C) /* Bias Control Register 1 */ +#define LVDS_PXBCR2(phy) ((phy) + 0x1030) /* Bias Control Register 2 */ +#define LVDS_PXBCR3(phy) ((phy) + 0x1034) /* Bias Control Register 3 */ +#define LVDS_PXMPLCR(phy) ((phy) + 0x1064) /* Monitor PLL Lock Control Register */ +#define LVDS_PXDCR(phy) ((phy) + 0x1084) /* Debug Control Register */ +#define LVDS_PXSSR1(phy) ((phy) + 0x1088) /* Spare Status Register 1 */ +#define LVDS_PXCFGCR(phy) ((phy) + 0x10A0) /* Configuration Control Register */ +#define LVDS_PXPLLCR1(phy) ((phy) + 0x10C0) /* PLL_MODE 1 Control Register */ +#define LVDS_PXPLLCR2(phy) ((phy) + 0x10C4) /* PLL_MODE 2 Control Register */ +#define LVDS_PXPLLSR(phy) ((phy) + 0x10C8) /* PLL Status Register */ +#define LVDS_PXPLLSDCR1(phy) ((phy) + 0x10CC) /* PLL_SD_1 Control Register */ +#define LVDS_PXPLLSDCR2(phy) ((phy) + 0x10D0) /* PLL_SD_2 Control Register */ +#define LVDS_PXPLLTWGCR1(phy) ((phy) + 0x10D4) /* PLL_TWG_1 Control Register */ +#define LVDS_PXPLLTWGCR2(phy) ((phy) + 0x10D8) /* PLL_TWG_2 Control Register */ +#define LVDS_PXPLLCPCR(phy) ((phy) + 0x10E0) /* PLL_CP Control Register */ +#define LVDS_PXPLLTESTCR(phy) ((phy) + 0x10E8) /* PLL_TEST Control Register */ + +/* LVDS Wrapper registers */ +#define LVDS_WCLKCR 0x11B0 /* Wrapper clock control register */ +#define LVDS_HWCFGR 0x1FF0 /* HW configuration register */ +#define LVDS_VERR 0x1FF4 /* Version register */ +#define LVDS_IPIDR 0x1FF8 /* Identification register */ +#define LVDS_SIDR 0x1FFC /* Size Identification register */ + +#define CR_LVDSEN BIT(0) /* LVDS PHY Enable */ +#define CR_HSPOL BIT(1) /* HS Polarity (horizontal sync) */ +#define CR_VSPOL BIT(2) /* VS Polarity (vertical sync) */ +#define CR_DEPOL BIT(3) /* DE Polarity (data enable) */ +#define CR_CI BIT(4) /* Control Internal (software controlled bit) */ +#define CR_LKMOD BIT(5) /* Link Mode, for both Links */ +#define CR_LKPHA BIT(6) /* Link Phase, for both Links */ +#define CR_LK1POL GENMASK(20, 16) /* Link-1 output Polarity */ +#define CR_LK2POL GENMASK(25, 21) /* Link-2 output Polarity */ + +#define DMMCRX_MAP0 GENMASK(4, 0) +#define DMMCRX_MAP1 GENMASK(9, 5) +#define DMMCRX_MAP2 GENMASK(14, 10) +#define DMMCRX_MAP3 GENMASK(19, 15) +#define DMLCRX_MAP4 GENMASK(4, 0) +#define DMLCRX_MAP5 GENMASK(9, 5) +#define DMLCRX_MAP6 GENMASK(14, 10) + +#define CDLCRX_DISTR0 GENMASK(3, 0) +#define CDLCRX_DISTR1 GENMASK(7, 4) +#define CDLCRX_DISTR2 GENMASK(11, 8) +#define CDLCRX_DISTR3 GENMASK(15, 12) +#define CDLCRX_DISTR4 GENMASK(19, 16) + +#define FREF_INDEX 0 +#define NDIV_INDEX 1 +#define FPFD_INDEX 2 +#define MDIV_INDEX 3 +#define FVCO_INDEX 4 +#define BDIV_INDEX 5 +#define FBIT_INDEX 6 +#define FLS_INDEX 7 +#define FDP_INDEX 8 + +#define PXGCR_BIT_CLK_OUT BIT(0) +#define PXGCR_LS_CLK_OUT BIT(4) +#define PXGCR_DP_CLK_OUT BIT(8) +#define PXGCR_RSTZ BIT(24) +#define PXGCR_DIV_RSTN BIT(25) + +#define PXCMCR1_CM_EN_DL (BIT(28) | BIT(20) | BIT(12) | BIT(4)) +#define PXCMCR2_CM_EN_DL4 BIT(4) +#define PXSCR_SER_DATA_OK BIT(16) +#define PXBCR1_EN_BIAS_DL (BIT(16) | BIT(12) | BIT(8) | BIT(4) | BIT(0)) +#define PXBCR2_BIAS_EN BIT(28) +#define PXBCR3_VM_EN_DL (BIT(16) | BIT(12) | BIT(8) | BIT(4) | BIT(0)) +#define PXDCR_POWER_OK BIT(12) +#define PXCFGCR_EN_DIG_DL GENMASK(4, 0) + +#define PXPLLCR1_PLL_EN BIT(0) +#define PxPLLCR1_SD_EN BIT(1) +#define PXPLLCR1_TWG_EN BIT(2) +#define PXPLLCR1_PLL_DIVIDERS_EN BIT(8) +#define PXPLLCR2_NDIV GENMASK(25, 16) +#define PXPLLCR2_BDIV GENMASK(9, 0) +#define PXPLLSR_PLL_LOCK BIT(0) +#define PXPLLSDCR1_MDIV GENMASK(9, 0) +#define PXPLLCPCR_CPCTRL_DEFAULT 0x1 +#define PXPLLTESTCR_PLL_TEST_CLK_EN BIT(0) +#define PXPLLTESTCR_PLL_TDIV_EN BIT(8) +#define PXPLLTESTCR_TDIV GENMASK(25, 16) +#define PXPLLTESTCR_TDIV_VALUE 70 + +#define WCLKCR_SLV_CLKPIX_SEL BIT(0) +#define WCLKCR_SRCSEL BIT(8) + +/* Sleep & timeout for pll lock/unlock */ +#define SLEEP_US 1000 +#define TIMEOUT_US 20000000 + +#define PHY_SLV_OFS 0x100 + +/* PLL parameters */ +#define NDIV_MIN 2 +#define NDIV_MAX 6 +#define BDIV_MIN 2 +#define BDIV_MAX 6 +#define MDIV_MIN 1 +#define MDIV_MAX 1023 + +struct stm32_lvds_plat { + void __iomem *base; + struct udevice *panel; + struct reset_ctl rst; + struct clk pclk; + struct clk refclk; +}; + +struct stm32_lvds_priv { + struct display_timing timings; + u32 refclk_rate; + int dual_link; + int bus_format; +}; + +/* + * enum lvds_pixels_order - Pixel order of an LVDS connection + * @LVDS_DUAL_LINK_EVEN_ODD_PIXELS: Even pixels are expected to be generated + * from the first port, odd pixels from the second port + * @LVDS_DUAL_LINK_ODD_EVEN_PIXELS: Odd pixels are expected to be generated + * from the first port, even pixels from the second port + */ +enum lvds_pixels_order { + LVDS_DUAL_LINK_EVEN_ODD_PIXELS = BIT(0), + LVDS_DUAL_LINK_ODD_EVEN_PIXELS = BIT(1), +}; + +enum lvds_pixel { + PIX_R_0 = 0x00, + PIX_R_1 = 0x01, + PIX_R_2 = 0x02, + PIX_R_3 = 0x03, + PIX_R_4 = 0x04, + PIX_R_5 = 0x05, + PIX_R_6 = 0x06, + PIX_R_7 = 0x07, + PIX_G_0 = 0x08, + PIX_G_1 = 0x09, + PIX_G_2 = 0x0A, + PIX_G_3 = 0x0B, + PIX_G_4 = 0x0C, + PIX_G_5 = 0x0D, + PIX_G_6 = 0x0E, + PIX_G_7 = 0x0F, + PIX_B_0 = 0x10, + PIX_B_1 = 0x11, + PIX_B_2 = 0x12, + PIX_B_3 = 0x13, + PIX_B_4 = 0x14, + PIX_B_5 = 0x15, + PIX_B_6 = 0x16, + PIX_B_7 = 0x17, + PIX_H_S = 0x18, + PIX_V_S = 0x19, + PIX_D_E = 0x1A, + PIX_C_E = 0x1B, + PIX_C_I = 0x1C, + PIX_TOG = 0x1D, + PIX_ONE = 0x1E, + PIX_ZER = 0x1F, +}; + +/* + * Expected JEIDA-RGB888 data to be sent in LSB format + * bit6 ............................bit0 + */ +const enum lvds_pixel lvds_bitmap_jeida_rgb888[5][7] = { + { PIX_ONE, PIX_ONE, PIX_ZER, PIX_ZER, PIX_ZER, PIX_ONE, PIX_ONE }, + { PIX_G_2, PIX_R_7, PIX_R_6, PIX_R_5, PIX_R_4, PIX_R_3, PIX_R_2 }, + { PIX_B_3, PIX_B_2, PIX_G_7, PIX_G_6, PIX_G_5, PIX_G_4, PIX_G_3 }, + { PIX_D_E, PIX_V_S, PIX_H_S, PIX_B_7, PIX_B_6, PIX_B_5, PIX_B_4 }, + { PIX_C_E, PIX_B_1, PIX_B_0, PIX_G_1, PIX_G_0, PIX_R_1, PIX_R_0 } +}; + +/* + * Expected VESA-RGB888 data to be sent in LSB format + * bit6 ............................bit0 + */ +const enum lvds_pixel lvds_bitmap_vesa_rgb888[5][7] = { + { PIX_ONE, PIX_ONE, PIX_ZER, PIX_ZER, PIX_ZER, PIX_ONE, PIX_ONE }, + { PIX_G_0, PIX_R_5, PIX_R_4, PIX_R_3, PIX_R_2, PIX_R_1, PIX_R_0 }, + { PIX_B_1, PIX_B_0, PIX_G_5, PIX_G_4, PIX_G_3, PIX_G_2, PIX_G_1 }, + { PIX_D_E, PIX_V_S, PIX_H_S, PIX_B_5, PIX_B_4, PIX_B_3, PIX_B_2 }, + { PIX_C_E, PIX_B_7, PIX_B_6, PIX_G_7, PIX_G_6, PIX_R_7, PIX_R_6 } +}; + +static inline void lvds_writel(void __iomem *base, u32 reg, u32 val) +{ + writel(val, base + reg); +} + +static inline u32 lvds_readl(void __iomem *base, u32 reg) +{ + return readl(base + reg); +} + +static inline void lvds_set(void __iomem *base, u32 reg, u32 mask) +{ + lvds_writel(base, reg, lvds_readl(base, reg) | mask); +} + +static inline void lvds_clear(void __iomem *base, u32 reg, u32 mask) +{ + lvds_writel(base, reg, lvds_readl(base, reg) & ~mask); +} + +static u32 pll_get_clkout_khz(u32 clkin_khz, u32 bdiv, u32 mdiv, u32 ndiv) +{ + int divisor = ndiv * bdiv; + + /* Prevents from division by 0 */ + if (!divisor) + return 0; + + return clkin_khz * mdiv / divisor; +} + +static int lvds_pll_get_params(u32 clkin_khz, u32 clkout_khz, + u32 *bdiv, u32 *mdiv, u32 *ndiv) +{ + u32 i, o, n; + u32 delta, best_delta; /* all in khz */ + + /* Early checks preventing division by 0 & odd results */ + if (clkin_khz == 0 || clkout_khz == 0) + return -EINVAL; + + best_delta = 1000000; /* big started value (1000000khz) */ + + for (i = NDIV_MIN; i <= NDIV_MAX; i++) { + for (o = BDIV_MIN; o <= BDIV_MAX; o++) { + n = DIV_ROUND_CLOSEST(i * o * clkout_khz, clkin_khz); + /* Check ndiv according to vco range */ + if (n < MDIV_MIN || n > MDIV_MAX) + continue; + /* Check if new delta is better & saves parameters */ + delta = abs(pll_get_clkout_khz(clkin_khz, i, n, o) - clkout_khz); + if (delta < best_delta) { + *ndiv = i; + *mdiv = n; + *bdiv = o; + best_delta = delta; + } + /* fast return in case of "perfect result" */ + if (!delta) + return 0; + } + } + + return 0; +} + +static int stm32_lvds_pll_enable(struct udevice *dev, + int phy) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + struct stm32_lvds_priv *priv = dev_get_priv(dev); + struct display_timing timings = priv->timings; + u32 pll_in_khz, bdiv = 0, mdiv = 0, ndiv = 0; + int ret, val, multiplier; + + /* Release PHY from reset */ + lvds_set(plat->base, LVDS_PXGCR(phy), PXGCR_DIV_RSTN | PXGCR_RSTZ); + + /* lvds_pll_config */ + /* Set PLL Slv & Mst configs and timings */ + pll_in_khz = priv->refclk_rate / 1000; + + if (priv->dual_link) + multiplier = 2; + else + multiplier = 1; + + ret = lvds_pll_get_params(pll_in_khz, timings.pixelclock.typ * 7 / 1000 / multiplier, + &bdiv, &mdiv, &ndiv); + if (ret) + return ret; + + /* Set PLL parameters */ + lvds_writel(plat->base, LVDS_PXPLLCR2(phy), (ndiv << 16) | bdiv); + lvds_writel(plat->base, LVDS_PXPLLSDCR1(phy), mdiv); + lvds_writel(plat->base, LVDS_PXPLLTESTCR(phy), PXPLLTESTCR_TDIV_VALUE << 16); + + /* Disable TWG and SD: for now, PLL just need to be in integer mode */ + lvds_clear(plat->base, LVDS_PXPLLCR1(phy), PXPLLCR1_TWG_EN | PxPLLCR1_SD_EN); + + /* Power up bias and PLL dividers */ + lvds_set(plat->base, LVDS_PXDCR(phy), PXDCR_POWER_OK); + + lvds_set(plat->base, LVDS_PXCMCR1(phy), PXCMCR1_CM_EN_DL); + lvds_set(plat->base, LVDS_PXCMCR2(phy), PXCMCR2_CM_EN_DL4); + + lvds_set(plat->base, LVDS_PXPLLCPCR(phy), PXPLLCPCR_CPCTRL_DEFAULT); + lvds_set(plat->base, LVDS_PXBCR3(phy), PXBCR3_VM_EN_DL); + lvds_set(plat->base, LVDS_PXBCR1(phy), PXBCR1_EN_BIAS_DL); + lvds_set(plat->base, LVDS_PXCFGCR(phy), PXCFGCR_EN_DIG_DL); + + /* lvds_pll_enable */ + /* PLL lock timing control for the monitor unmask after startup (pll_en) */ + /* Adjust the value so that the masking window is opened at start-up */ + /* MST_MON_PLL_LOCK_UNMASK_TUNE */ + lvds_writel(plat->base, LVDS_PXMPLCR(phy), (0x200 - 0x160) << 16); + + lvds_writel(plat->base, LVDS_PXBCR2(phy), PXBCR2_BIAS_EN); + + lvds_set(plat->base, LVDS_PXGCR(phy), + PXGCR_DP_CLK_OUT | PXGCR_LS_CLK_OUT | PXGCR_BIT_CLK_OUT); + + lvds_set(plat->base, LVDS_PXPLLTESTCR(phy), PXPLLTESTCR_PLL_TDIV_EN); + lvds_set(plat->base, LVDS_PXPLLCR1(phy), PXPLLCR1_PLL_DIVIDERS_EN); + lvds_set(plat->base, LVDS_PXSCR(phy), PXSCR_SER_DATA_OK); + + /* Enable the LVDS PLL & wait for its lock */ + lvds_set(plat->base, LVDS_PXPLLCR1(phy), PXPLLCR1_PLL_EN); + ret = readl_poll_sleep_timeout(plat->base + LVDS_PXPLLSR(phy), + val, val & PXPLLSR_PLL_LOCK, SLEEP_US, TIMEOUT_US); + if (ret) + return ret; + + /* Select MST PHY clock as pixel clock for the LDITX instead of FREF */ + /* WCLKCR_SLV_CLKPIX_SEL is for dual link */ + lvds_writel(plat->base, LVDS_WCLKCR, WCLKCR_SLV_CLKPIX_SEL); + + lvds_set(plat->base, LVDS_PXPLLTESTCR(phy), PXPLLTESTCR_PLL_TEST_CLK_EN); + + return 0; +} + +static int stm32_lvds_enable(struct udevice *dev) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + struct stm32_lvds_priv *priv = dev_get_priv(dev); + struct display_timing timings = priv->timings; + u32 lvds_cdl1cr = 0; + u32 lvds_cdl2cr = 0; + u32 lvds_dmlcr = 0; + u32 lvds_dmmcr = 0; + u32 lvds_cr = 0; + int i; + + lvds_clear(plat->base, LVDS_CDL1CR, CDLCRX_DISTR0 | CDLCRX_DISTR1 | CDLCRX_DISTR2 + | CDLCRX_DISTR3 | CDLCRX_DISTR4); + lvds_clear(plat->base, LVDS_CDL2CR, CDLCRX_DISTR0 | CDLCRX_DISTR1 | CDLCRX_DISTR2 + | CDLCRX_DISTR3 | CDLCRX_DISTR4); + + /* Set channel distribution */ + lvds_cr &= ~CR_LKMOD; + lvds_cdl1cr = CDL1CR_DEFAULT; + + if (priv->dual_link) { + lvds_cr |= CR_LKMOD; + lvds_cdl2cr = CDL2CR_DEFAULT; + } + + /* Set signal polarity */ + if (timings.flags & DISPLAY_FLAGS_DE_LOW) + lvds_cr |= CR_DEPOL; + + if (timings.flags & DISPLAY_FLAGS_HSYNC_LOW) + lvds_cr |= CR_HSPOL; + + if (timings.flags & DISPLAY_FLAGS_VSYNC_LOW) + lvds_cr |= CR_VSPOL; + + /* Set link phase */ + switch (priv->dual_link) { + case LVDS_DUAL_LINK_EVEN_ODD_PIXELS: /* LKPHA = 0 */ + lvds_cr &= ~CR_LKPHA; + break; + case LVDS_DUAL_LINK_ODD_EVEN_PIXELS: /* LKPHA = 1 */ + lvds_cr |= CR_LKPHA; + break; + default: + dev_dbg(dev, "No phase precised, setting default\n"); + lvds_cr &= ~CR_LKPHA; + break; + } + + /* Set Data Mapping */ + switch (priv->bus_format) { + case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG: /* VESA-RGB888 */ + for (i = 0; i < 5; i++) { + lvds_dmlcr = ((lvds_bitmap_vesa_rgb888[i][0]) + + (lvds_bitmap_vesa_rgb888[i][1] << 5) + + (lvds_bitmap_vesa_rgb888[i][2] << 10) + + (lvds_bitmap_vesa_rgb888[i][3] << 15)); + lvds_dmmcr = ((lvds_bitmap_vesa_rgb888[i][4]) + + (lvds_bitmap_vesa_rgb888[i][5] << 5) + + (lvds_bitmap_vesa_rgb888[i][6] << 10)); + + /* Write registers at the end of computations */ + lvds_writel(plat->base, LVDS_DMLCR(i), lvds_dmlcr); + lvds_writel(plat->base, LVDS_DMMCR(i), lvds_dmmcr); + } + break; + case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA: /* JEIDA-RGB888 */ + for (i = 0; i < 5; i++) { + lvds_dmlcr = ((lvds_bitmap_jeida_rgb888[i][0]) + + (lvds_bitmap_jeida_rgb888[i][1] << 5) + + (lvds_bitmap_jeida_rgb888[i][2] << 10) + + (lvds_bitmap_jeida_rgb888[i][3] << 15)); + lvds_dmmcr = ((lvds_bitmap_jeida_rgb888[i][4]) + + (lvds_bitmap_jeida_rgb888[i][5] << 5) + + (lvds_bitmap_jeida_rgb888[i][6] << 10)); + + /* Write registers at the end of computations */ + lvds_writel(plat->base, LVDS_DMLCR(i), lvds_dmlcr); + lvds_writel(plat->base, LVDS_DMMCR(i), lvds_dmmcr); + } + break; + default: + dev_dbg(dev, "Unsupported LVDS bus format 0x%04x\n", priv->bus_format); + } + + /* Turn the output on */ + lvds_cr |= CR_LVDSEN; + + /* Commit config to registers */ + lvds_set(plat->base, LVDS_CR, lvds_cr); + lvds_writel(plat->base, LVDS_CDL1CR, lvds_cdl1cr); + lvds_writel(plat->base, LVDS_CDL2CR, lvds_cdl2cr); + + return 0; +} + +static int stm32_lvds_attach(struct udevice *dev) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + struct stm32_lvds_priv *priv = dev_get_priv(dev); + int ret; + + ret = panel_get_display_timing(plat->panel, &priv->timings); + if (ret) { + ret = ofnode_decode_display_timing(dev_ofnode(plat->panel), + 0, &priv->timings); + if (ret) { + dev_err(dev, "decode display timing error %d\n", ret); + return ret; + } + } + + ret = stm32_lvds_enable(dev); + + return ret; +} + +static int stm32_lvds_set_backlight(struct udevice *dev, int percent) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + int ret; + + ret = panel_enable_backlight(plat->panel); + if (ret) { + dev_err(dev, "panel %s enable backlight error %d\n", + plat->panel->name, ret); + } + + return ret; +} + +static int lvds_handle_pixel_order(struct stm32_lvds_plat *plat) +{ + ofnode parent, panel_port0, panel_port1; + bool even_pixels, odd_pixels; + int port0, port1; + + /* + * In case we are operating in single link, + * there is only one port linked to the LVDS. + * Check whether we are in this case and exit if yes. + */ + parent = ofnode_find_subnode(dev_ofnode(plat->panel), "ports"); + if (!ofnode_valid(parent)) + return 0; + + panel_port0 = ofnode_first_subnode(parent); + if (!ofnode_valid(panel_port0)) + return -EPIPE; + + even_pixels = ofnode_read_bool(panel_port0, "dual-lvds-even-pixels"); + odd_pixels = ofnode_read_bool(panel_port0, "dual-lvds-odd-pixels"); + if (even_pixels && odd_pixels) + return -EINVAL; + + port0 = even_pixels ? LVDS_DUAL_LINK_EVEN_ODD_PIXELS : + LVDS_DUAL_LINK_ODD_EVEN_PIXELS; + + panel_port1 = ofnode_next_subnode(panel_port0); + if (!ofnode_valid(panel_port1)) + return -EPIPE; + + even_pixels = ofnode_read_bool(panel_port1, "dual-lvds-even-pixels"); + odd_pixels = ofnode_read_bool(panel_port1, "dual-lvds-odd-pixels"); + if (even_pixels && odd_pixels) + return -EINVAL; + + port1 = even_pixels ? LVDS_DUAL_LINK_EVEN_ODD_PIXELS : + LVDS_DUAL_LINK_ODD_EVEN_PIXELS; + + /* + * A valid dual-LVDS bus is found when one port is marked with + * "dual-lvds-even-pixels", and the other port is marked with + * "dual-lvds-odd-pixels", bail out if the markers are not right. + */ + if (port0 + port1 != LVDS_DUAL_LINK_EVEN_ODD_PIXELS + LVDS_DUAL_LINK_ODD_EVEN_PIXELS) + return -EINVAL; + + return port0; +} + +static int stm32_lvds_of_to_plat(struct udevice *dev) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + struct stm32_lvds_priv *priv = dev_get_priv(dev); + const char *data_mapping; + int ret; + + plat->base = dev_read_addr_ptr(dev); + if ((fdt_addr_t)plat->base == FDT_ADDR_T_NONE) { + dev_err(dev, "Unable to read LVDS base address\n"); + return -EINVAL; + } + + ret = clk_get_by_name(dev, "pclk", &plat->pclk); + if (ret) { + dev_err(dev, "Unable to get peripheral clock: %d\n", ret); + return ret; + } + + ret = clk_get_by_name(dev, "ref", &plat->refclk); + if (ret) { + dev_err(dev, "Unable to get reference clock: %d\n", ret); + return ret; + } + + ret = reset_get_by_index(dev, 0, &plat->rst); + if (ret) { + dev_err(dev, "Failed to get LVDS reset: %d\n", ret); + return ret; + } + + ret = uclass_get_device_by_driver(UCLASS_PANEL, + DM_DRIVER_GET(simple_panel), &plat->panel); + if (ret) { + dev_err(dev, "panel device error %d\n", ret); + return ret; + } + + ret = panel_get_display_timing(plat->panel, &priv->timings); + if (ret) { + ret = ofnode_decode_display_timing(dev_ofnode(plat->panel), + 0, &priv->timings); + if (ret) { + dev_err(dev, "decode display timing error %d\n", ret); + return ret; + } + } + + data_mapping = ofnode_read_string(dev_ofnode(plat->panel), "data-mapping"); + if (!strcmp(data_mapping, "vesa-24")) + priv->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG; + else if (!strcmp(data_mapping, "jeida-24")) + priv->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA; + else + priv->bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG; + + return 0; +} + +static int stm32_lvds_probe(struct udevice *dev) +{ + struct stm32_lvds_plat *plat = dev_get_plat(dev); + struct stm32_lvds_priv *priv = dev_get_priv(dev); + int ret; + + ret = clk_enable(&plat->pclk); + if (ret) { + dev_err(dev, "Failed to enable peripheral clock: %d\n", ret); + return ret; + } + + ret = clk_enable(&plat->refclk); + if (ret) { + dev_err(dev, "Failed to enable reference clock: %d\n", ret); + goto err_clk; + } + + priv->refclk_rate = (unsigned int)clk_get_rate(&plat->refclk); + + reset_deassert(&plat->rst); + + /* Handle dual link config */ + priv->dual_link = lvds_handle_pixel_order(plat); + if (priv->dual_link < 0) + goto err_rst; + + if (priv->dual_link > 0) { + ret = stm32_lvds_pll_enable(dev, LVDS_PHY_SLAVE); + if (ret) + goto err_rst; + } + + ret = stm32_lvds_pll_enable(dev, LVDS_PHY_MASTER); + if (ret) + goto err_rst; + + return 0; + +err_rst: + clk_disable(&plat->refclk); +err_clk: + clk_disable(&plat->pclk); + + return ret; +} + +static const struct video_bridge_ops stm32_lvds_ops = { + .attach = stm32_lvds_attach, + .set_backlight = stm32_lvds_set_backlight, +}; + +static const struct udevice_id stm32_lvds_ids[] = { + {.compatible = "st,stm32mp25-lvds"}, + {} +}; + +U_BOOT_DRIVER(stm32_lvds) = { + .name = "stm32-display-lvds", + .id = UCLASS_VIDEO_BRIDGE, + .of_match = stm32_lvds_ids, + .ops = &stm32_lvds_ops, + .of_to_plat = stm32_lvds_of_to_plat, + .probe = stm32_lvds_probe, + .plat_auto = sizeof(struct stm32_lvds_plat), + .priv_auto = sizeof(struct stm32_lvds_priv), +}; |
