diff options
Diffstat (limited to 'drivers')
98 files changed, 2850 insertions, 1526 deletions
diff --git a/drivers/cache/cache-sifive-ccache.c b/drivers/cache/cache-sifive-ccache.c index 76c0ab26ae3..c8766f62427 100644 --- a/drivers/cache/cache-sifive-ccache.c +++ b/drivers/cache/cache-sifive-ccache.c @@ -38,7 +38,7 @@ static int sifive_ccache_get_info(struct udevice *dev, struct cache_info *info) { struct sifive_ccache *priv = dev_get_priv(dev); - info->base = (phys_addr_t)priv->base; + info->base = (uintptr_t)priv->base; return 0; } diff --git a/drivers/clk/clk_fixed_rate.c b/drivers/clk/clk_fixed_rate.c index e0dc4ab85f8..c5a2a42c923 100644 --- a/drivers/clk/clk_fixed_rate.c +++ b/drivers/clk/clk_fixed_rate.c @@ -26,6 +26,7 @@ static int dummy_enable(struct clk *clk) const struct clk_ops clk_fixed_rate_ops = { .get_rate = clk_fixed_rate_get_rate, .enable = dummy_enable, + .disable = dummy_enable, }; void clk_fixed_rate_ofdata_to_plat_(struct udevice *dev, diff --git a/drivers/clk/clk_kendryte.c b/drivers/clk/clk_kendryte.c index 31487569686..97efda5b6f0 100644 --- a/drivers/clk/clk_kendryte.c +++ b/drivers/clk/clk_kendryte.c @@ -709,6 +709,10 @@ TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in, * Whether we swapped r and od while enforcing frequency limits */ bool swapped = false; + /* + * Whether the intermediate frequencies are out-of-spec + */ + bool out_of_spec; u64 last_od = od; u64 last_r = r; @@ -767,76 +771,95 @@ TEST_STATIC int k210_pll_calc_config(u32 rate, u32 rate_in, * aren't in spec, try swapping r and od. If everything is * in-spec, calculate the relative error. */ - while (true) { +again: + out_of_spec = false; + if (r > max_r) { + out_of_spec = true; + } else { /* - * Whether the intermediate frequencies are out-of-spec + * There is no way to only divide once; we need + * to examine the frequency with and without the + * effect of od. */ - bool out_of_spec = false; + u64 vco = DIV_ROUND_CLOSEST_ULL(rate_in * f, r); - if (r > max_r) { + if (vco > 1750000000 || vco < 340000000) out_of_spec = true; - } else { - /* - * There is no way to only divide once; we need - * to examine the frequency with and without the - * effect of od. - */ - u64 vco = DIV_ROUND_CLOSEST_ULL(rate_in * f, r); + } + + if (out_of_spec) { + u64 new_r, new_od; + + if (!swapped) { + u64 tmp = r; - if (vco > 1750000000 || vco < 340000000) - out_of_spec = true; + r = od; + od = tmp; + swapped = true; + goto again; } - if (out_of_spec) { - if (!swapped) { - u64 tmp = r; - - r = od; - od = tmp; - swapped = true; - continue; - } else { - /* - * Try looking ahead to see if there are - * additional factors for the same - * product. - */ - if (i + 1 < ARRAY_SIZE(factors)) { - u64 new_r, new_od; - - i++; - new_r = UNPACK_R(factors[i]); - new_od = UNPACK_OD(factors[i]); - if (r * od == new_r * new_od) { - r = new_r; - od = new_od; - swapped = false; - continue; - } - i--; + /* + * Try looking ahead to see if there are additional + * factors for the same product. + */ + if (i + 1 < ARRAY_SIZE(factors)) { + i++; + new_r = UNPACK_R(factors[i]); + new_od = UNPACK_OD(factors[i]); + if (r * od == new_r * new_od) { + r = new_r; + od = new_od; + swapped = false; + goto again; + } + i--; + } + + /* + * Try looking back to see if there is a worse ratio + * that we could try anyway + */ + while (i > 0) { + i--; + new_r = UNPACK_R(factors[i]); + new_od = UNPACK_OD(factors[i]); + /* + * Don't loop over factors for the same product + * to avoid getting stuck because of the above + * clause + */ + if (r * od != new_r * new_od) { + if (new_r * new_od > last_r * last_od) { + r = new_r; + od = new_od; + swapped = false; + goto again; } break; } } - error = DIV_ROUND_CLOSEST_ULL(f * inv_ratio, r * od); - /* The lower 16 bits are spurious */ - error = abs((error - BIT(32))) >> 16; + /* We ran out of things to try */ + continue; + } - if (error < best_error) { - best->r = r; - best->f = f; - best->od = od; - best_error = error; - } - break; + error = DIV_ROUND_CLOSEST_ULL(f * inv_ratio, r * od); + /* The lower 16 bits are spurious */ + error = abs((error - BIT(32))) >> 16; + + if (error < best_error) { + best->r = r; + best->f = f; + best->od = od; + best_error = error; } } while (f < 64 && i + 1 < ARRAY_SIZE(factors) && error != 0); + log_debug("best error %lld\n", best_error); if (best_error == S64_MAX) return -EINVAL; - log_debug("best error %lld\n", best_error); return 0; } @@ -849,9 +872,6 @@ static ulong k210_pll_set_rate(struct k210_clk_priv *priv, int id, ulong rate, u32 reg; ulong calc_rate; - if (rate_in < 0) - return rate_in; - err = k210_pll_calc_config(rate, rate_in, &config); if (err) return err; @@ -895,7 +915,7 @@ static ulong k210_pll_get_rate(struct k210_clk_priv *priv, int id, u64 r, f, od; u32 reg = readl(priv->base + k210_plls[id].off); - if (rate_in < 0 || (reg & K210_PLL_BYPASS)) + if (reg & K210_PLL_BYPASS) return rate_in; if (!(reg & K210_PLL_PWRD)) @@ -1029,6 +1049,8 @@ static ulong do_k210_clk_get_rate(struct k210_clk_priv *priv, int id) parent = k210_clk_get_parent(priv, id); parent_rate = do_k210_clk_get_rate(priv, parent); + if (IS_ERR_VALUE(parent_rate)) + return parent_rate; if (k210_clks[id].flags & K210_CLKF_PLL) return k210_pll_get_rate(priv, k210_clks[id].pll, parent_rate); @@ -1099,6 +1121,8 @@ static ulong k210_clk_set_rate(struct clk *clk, unsigned long rate) parent = k210_clk_get_parent(priv, clk->id); rate_in = do_k210_clk_get_rate(priv, parent); + if (IS_ERR_VALUE(rate_in)) + return rate_in; log_debug("id=%ld rate=%lu rate_in=%lu\n", clk->id, rate, rate_in); diff --git a/drivers/clk/rockchip/clk_px30.c b/drivers/clk/rockchip/clk_px30.c index 617ce0dce5a..ea874e3f4b9 100644 --- a/drivers/clk/rockchip/clk_px30.c +++ b/drivers/clk/rockchip/clk_px30.c @@ -1291,6 +1291,9 @@ static ulong px30_clk_set_rate(struct clk *clk, ulong rate) case PLL_NPLL: ret = px30_clk_set_pll_rate(priv, NPLL, rate); break; + case PLL_CPLL: + ret = px30_clk_set_pll_rate(priv, CPLL, rate); + break; case ARMCLK: ret = px30_armclk_set_clk(priv, rate); break; diff --git a/drivers/clk/rockchip/clk_rk3568.c b/drivers/clk/rockchip/clk_rk3568.c index 553c6c0dafb..d5e45e7602c 100644 --- a/drivers/clk/rockchip/clk_rk3568.c +++ b/drivers/clk/rockchip/clk_rk3568.c @@ -1441,6 +1441,7 @@ static ulong rk3568_sdmmc_set_clk(struct rk3568_clk_priv *priv, switch (rate) { case OSC_HZ: + case 26 * MHz: src_clk = CLK_SDMMC_SEL_24M; break; case 400 * MHz: @@ -1507,7 +1508,7 @@ static ulong rk3568_sfc_get_clk(struct rk3568_clk_priv *priv) case SCLK_SFC_SEL_125M: return 125 * MHz; case SCLK_SFC_SEL_150M: - return 150 * KHz; + return 150 * MHz; default: return -ENOENT; } @@ -1534,7 +1535,7 @@ static ulong rk3568_sfc_set_clk(struct rk3568_clk_priv *priv, ulong rate) case 125 * MHz: src_clk = SCLK_SFC_SEL_125M; break; - case 150 * KHz: + case 150 * MHz: src_clk = SCLK_SFC_SEL_150M; break; default: @@ -2406,6 +2407,9 @@ static ulong rk3568_clk_get_rate(struct clk *clk) case BCLK_EMMC: rate = rk3568_emmc_get_bclk(priv); break; + case TCLK_EMMC: + rate = OSC_HZ; + break; #ifndef CONFIG_SPL_BUILD case ACLK_VOP: rate = rk3568_aclk_vop_get_clk(priv); @@ -2582,6 +2586,9 @@ static ulong rk3568_clk_set_rate(struct clk *clk, ulong rate) case BCLK_EMMC: ret = rk3568_emmc_set_bclk(priv, rate); break; + case TCLK_EMMC: + ret = OSC_HZ; + break; #ifndef CONFIG_SPL_BUILD case ACLK_VOP: ret = rk3568_aclk_vop_set_clk(priv, rate); diff --git a/drivers/clk/sifive/sifive-prci.c b/drivers/clk/sifive/sifive-prci.c index cd1acb94429..52ae268e0c8 100644 --- a/drivers/clk/sifive/sifive-prci.c +++ b/drivers/clk/sifive/sifive-prci.c @@ -653,9 +653,9 @@ static int sifive_prci_probe(struct udevice *dev) struct prci_clk_desc *data = (struct prci_clk_desc *)dev_get_driver_data(dev); - pd->va = (void *)dev_read_addr(dev); - if (IS_ERR(pd->va)) - return PTR_ERR(pd->va); + pd->va = dev_read_addr_ptr(dev); + if (!pd->va) + return -EINVAL; err = clk_get_by_index(dev, 0, &pd->parent_hfclk); if (err) diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig index bf084fa7a84..f89c7ffd42a 100644 --- a/drivers/clk/sunxi/Kconfig +++ b/drivers/clk/sunxi/Kconfig @@ -30,6 +30,13 @@ config CLK_SUN6I_A31 This enables common clock driver support for platforms based on Allwinner A31/A31s SoC. +config CLK_SUN6I_A31_R + bool "Clock driver for Allwinner A31 generation PRCM" + default SUNXI_GEN_SUN6I + help + This enables common clock driver support for the PRCM + in Allwinner A31/A31s/A23/A33/A83T/H3/A64/H5 SoCs. + config CLK_SUN8I_A23 bool "Clock driver for Allwinner A23/A33" default MACH_SUN8I_A23 || MACH_SUN8I_A33 @@ -79,6 +86,13 @@ config CLK_SUN50I_H6 This enables common clock driver support for platforms based on Allwinner H6 SoC. +config CLK_SUN50I_H6_R + bool "Clock driver for Allwinner H6 generation PRCM" + default SUN50I_GEN_H6 + help + This enables common clock driver support for the PRCM + in Allwinner H6/H616 SoCs. + config CLK_SUN50I_H616 bool "Clock driver for Allwinner H616" default MACH_SUN50I_H616 diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 4f9282a8b9b..48a48a2f000 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_CLK_SUNXI) += clk_sun6i_rtc.o obj-$(CONFIG_CLK_SUN4I_A10) += clk_a10.o obj-$(CONFIG_CLK_SUN5I_A10S) += clk_a10s.o obj-$(CONFIG_CLK_SUN6I_A31) += clk_a31.o +obj-$(CONFIG_CLK_SUN6I_A31_R) += clk_a31_r.o obj-$(CONFIG_CLK_SUN8I_A23) += clk_a23.o obj-$(CONFIG_CLK_SUN8I_A83T) += clk_a83t.o obj-$(CONFIG_CLK_SUN8I_R40) += clk_r40.o @@ -18,5 +19,6 @@ obj-$(CONFIG_CLK_SUN8I_V3S) += clk_v3s.o obj-$(CONFIG_CLK_SUN9I_A80) += clk_a80.o obj-$(CONFIG_CLK_SUN8I_H3) += clk_h3.o obj-$(CONFIG_CLK_SUN50I_H6) += clk_h6.o +obj-$(CONFIG_CLK_SUN50I_H6_R) += clk_h6_r.o obj-$(CONFIG_CLK_SUN50I_H616) += clk_h616.o obj-$(CONFIG_CLK_SUN50I_A64) += clk_a64.o diff --git a/drivers/clk/sunxi/clk_a10.c b/drivers/clk/sunxi/clk_a10.c index 1b5de86e204..90b929d3d32 100644 --- a/drivers/clk/sunxi/clk_a10.c +++ b/drivers/clk/sunxi/clk_a10.c @@ -8,7 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun4i-a10-ccu.h> #include <dt-bindings/reset/sun4i-a10-ccu.h> #include <linux/bitops.h> @@ -31,6 +31,11 @@ static struct ccu_clk_gate a10_gates[] = { [CLK_AHB_GMAC] = GATE(0x064, BIT(17)), + [CLK_APB1_I2C0] = GATE(0x06c, BIT(0)), + [CLK_APB1_I2C1] = GATE(0x06c, BIT(1)), + [CLK_APB1_I2C2] = GATE(0x06c, BIT(2)), + [CLK_APB1_I2C3] = GATE(0x06c, BIT(3)), + [CLK_APB1_I2C4] = GATE(0x06c, BIT(15)), [CLK_APB1_UART0] = GATE(0x06c, BIT(16)), [CLK_APB1_UART1] = GATE(0x06c, BIT(17)), [CLK_APB1_UART2] = GATE(0x06c, BIT(18)), diff --git a/drivers/clk/sunxi/clk_a10s.c b/drivers/clk/sunxi/clk_a10s.c index 184f61ab234..addf4f4d5cd 100644 --- a/drivers/clk/sunxi/clk_a10s.c +++ b/drivers/clk/sunxi/clk_a10s.c @@ -8,7 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun5i-ccu.h> #include <dt-bindings/reset/sun5i-ccu.h> #include <linux/bitops.h> @@ -25,6 +25,9 @@ static struct ccu_clk_gate a10s_gates[] = { [CLK_AHB_SPI1] = GATE(0x060, BIT(21)), [CLK_AHB_SPI2] = GATE(0x060, BIT(22)), + [CLK_APB1_I2C0] = GATE(0x06c, BIT(0)), + [CLK_APB1_I2C1] = GATE(0x06c, BIT(1)), + [CLK_APB1_I2C2] = GATE(0x06c, BIT(2)), [CLK_APB1_UART0] = GATE(0x06c, BIT(16)), [CLK_APB1_UART1] = GATE(0x06c, BIT(17)), [CLK_APB1_UART2] = GATE(0x06c, BIT(18)), diff --git a/drivers/clk/sunxi/clk_a23.c b/drivers/clk/sunxi/clk_a23.c index 5750514a74f..c45d2c35298 100644 --- a/drivers/clk/sunxi/clk_a23.c +++ b/drivers/clk/sunxi/clk_a23.c @@ -8,7 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun8i-a23-a33-ccu.h> #include <dt-bindings/reset/sun8i-a23-a33-ccu.h> #include <linux/bitops.h> @@ -23,6 +23,9 @@ static struct ccu_clk_gate a23_gates[] = { [CLK_BUS_EHCI] = GATE(0x060, BIT(26)), [CLK_BUS_OHCI] = GATE(0x060, BIT(29)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), + [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), + [CLK_BUS_I2C2] = GATE(0x06c, BIT(2)), [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), @@ -53,6 +56,9 @@ static struct ccu_reset a23_resets[] = { [RST_BUS_EHCI] = RESET(0x2c0, BIT(26)), [RST_BUS_OHCI] = RESET(0x2c0, BIT(29)), + [RST_BUS_I2C0] = RESET(0x2d8, BIT(0)), + [RST_BUS_I2C1] = RESET(0x2d8, BIT(1)), + [RST_BUS_I2C2] = RESET(0x2d8, BIT(2)), [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), [RST_BUS_UART1] = RESET(0x2d8, BIT(17)), [RST_BUS_UART2] = RESET(0x2d8, BIT(18)), diff --git a/drivers/clk/sunxi/clk_a31.c b/drivers/clk/sunxi/clk_a31.c index 9226112f4af..251fc3b705e 100644 --- a/drivers/clk/sunxi/clk_a31.c +++ b/drivers/clk/sunxi/clk_a31.c @@ -8,7 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun6i-a31-ccu.h> #include <dt-bindings/reset/sun6i-a31-ccu.h> #include <linux/bitops.h> @@ -30,6 +30,10 @@ static struct ccu_clk_gate a31_gates[] = { [CLK_AHB1_OHCI1] = GATE(0x060, BIT(30)), [CLK_AHB1_OHCI2] = GATE(0x060, BIT(31)), + [CLK_APB2_I2C0] = GATE(0x06c, BIT(0)), + [CLK_APB2_I2C1] = GATE(0x06c, BIT(1)), + [CLK_APB2_I2C2] = GATE(0x06c, BIT(2)), + [CLK_APB2_I2C3] = GATE(0x06c, BIT(3)), [CLK_APB2_UART0] = GATE(0x06c, BIT(16)), [CLK_APB2_UART1] = GATE(0x06c, BIT(17)), [CLK_APB2_UART2] = GATE(0x06c, BIT(18)), @@ -71,6 +75,10 @@ static struct ccu_reset a31_resets[] = { [RST_AHB1_OHCI1] = RESET(0x2c0, BIT(30)), [RST_AHB1_OHCI2] = RESET(0x2c0, BIT(31)), + [RST_APB2_I2C0] = RESET(0x2d8, BIT(0)), + [RST_APB2_I2C1] = RESET(0x2d8, BIT(1)), + [RST_APB2_I2C2] = RESET(0x2d8, BIT(2)), + [RST_APB2_I2C3] = RESET(0x2d8, BIT(3)), [RST_APB2_UART0] = RESET(0x2d8, BIT(16)), [RST_APB2_UART1] = RESET(0x2d8, BIT(17)), [RST_APB2_UART2] = RESET(0x2d8, BIT(18)), diff --git a/drivers/clk/sunxi/clk_a31_r.c b/drivers/clk/sunxi/clk_a31_r.c new file mode 100644 index 00000000000..1f08ea956f9 --- /dev/null +++ b/drivers/clk/sunxi/clk_a31_r.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) Samuel Holland <samuel@sholland.org> + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <clk/sunxi.h> +#include <dt-bindings/clock/sun8i-r-ccu.h> +#include <dt-bindings/reset/sun8i-r-ccu.h> +#include <linux/bitops.h> + +static struct ccu_clk_gate a31_r_gates[] = { + [CLK_APB0_PIO] = GATE(0x028, BIT(0)), + [CLK_APB0_IR] = GATE(0x028, BIT(1)), + [CLK_APB0_TIMER] = GATE(0x028, BIT(2)), + [CLK_APB0_RSB] = GATE(0x028, BIT(3)), + [CLK_APB0_UART] = GATE(0x028, BIT(4)), + [CLK_APB0_I2C] = GATE(0x028, BIT(6)), + [CLK_APB0_TWD] = GATE(0x028, BIT(7)), +}; + +static struct ccu_reset a31_r_resets[] = { + [RST_APB0_IR] = RESET(0x0b0, BIT(1)), + [RST_APB0_TIMER] = RESET(0x0b0, BIT(2)), + [RST_APB0_RSB] = RESET(0x0b0, BIT(3)), + [RST_APB0_UART] = RESET(0x0b0, BIT(4)), + [RST_APB0_I2C] = RESET(0x0b0, BIT(6)), +}; + +static const struct ccu_desc a31_r_ccu_desc = { + .gates = a31_r_gates, + .resets = a31_r_resets, +}; + +static int a31_r_clk_bind(struct udevice *dev) +{ + return sunxi_reset_bind(dev, ARRAY_SIZE(a31_r_resets)); +} + +static const struct udevice_id a31_r_clk_ids[] = { + { .compatible = "allwinner,sun8i-a83t-r-ccu", + .data = (ulong)&a31_r_ccu_desc }, + { .compatible = "allwinner,sun8i-h3-r-ccu", + .data = (ulong)&a31_r_ccu_desc }, + { .compatible = "allwinner,sun50i-a64-r-ccu", + .data = (ulong)&a31_r_ccu_desc }, + { } +}; + +U_BOOT_DRIVER(clk_sun6i_a31_r) = { + .name = "sun6i_a31_r_ccu", + .id = UCLASS_CLK, + .of_match = a31_r_clk_ids, + .priv_auto = sizeof(struct ccu_priv), + .ops = &sunxi_clk_ops, + .probe = sunxi_clk_probe, + .bind = a31_r_clk_bind, +}; diff --git a/drivers/clk/sunxi/clk_a64.c b/drivers/clk/sunxi/clk_a64.c index 0553ffa4399..1004a795033 100644 --- a/drivers/clk/sunxi/clk_a64.c +++ b/drivers/clk/sunxi/clk_a64.c @@ -8,7 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun50i-a64-ccu.h> #include <dt-bindings/reset/sun50i-a64-ccu.h> #include <linux/bitops.h> @@ -26,6 +26,9 @@ static const struct ccu_clk_gate a64_gates[] = { [CLK_BUS_OHCI0] = GATE(0x060, BIT(28)), [CLK_BUS_OHCI1] = GATE(0x060, BIT(29)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), + [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), + [CLK_BUS_I2C2] = GATE(0x06c, BIT(2)), [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), @@ -60,6 +63,9 @@ static const struct ccu_reset a64_resets[] = { [RST_BUS_OHCI0] = RESET(0x2c0, BIT(28)), [RST_BUS_OHCI1] = RESET(0x2c0, BIT(29)), + [RST_BUS_I2C0] = RESET(0x2d8, BIT(0)), + [RST_BUS_I2C1] = RESET(0x2d8, BIT(1)), + [RST_BUS_I2C2] = RESET(0x2d8, BIT(2)), [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), [RST_BUS_UART1] = RESET(0x2d8, BIT(17)), [RST_BUS_UART2] = RESET(0x2d8, BIT(18)), diff --git a/drivers/clk/sunxi/clk_a80.c b/drivers/clk/sunxi/clk_a80.c index 68973d528ed..8a0834d83a3 100644 --- a/drivers/clk/sunxi/clk_a80.c +++ b/drivers/clk/sunxi/clk_a80.c @@ -8,7 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun9i-a80-ccu.h> #include <dt-bindings/reset/sun9i-a80-ccu.h> #include <linux/bitops.h> @@ -25,6 +25,11 @@ static const struct ccu_clk_gate a80_gates[] = { [CLK_BUS_SPI2] = GATE(0x580, BIT(22)), [CLK_BUS_SPI3] = GATE(0x580, BIT(23)), + [CLK_BUS_I2C0] = GATE(0x594, BIT(0)), + [CLK_BUS_I2C1] = GATE(0x594, BIT(1)), + [CLK_BUS_I2C2] = GATE(0x594, BIT(2)), + [CLK_BUS_I2C3] = GATE(0x594, BIT(3)), + [CLK_BUS_I2C4] = GATE(0x594, BIT(4)), [CLK_BUS_UART0] = GATE(0x594, BIT(16)), [CLK_BUS_UART1] = GATE(0x594, BIT(17)), [CLK_BUS_UART2] = GATE(0x594, BIT(18)), @@ -40,6 +45,11 @@ static const struct ccu_reset a80_resets[] = { [RST_BUS_SPI2] = RESET(0x5a0, BIT(22)), [RST_BUS_SPI3] = RESET(0x5a0, BIT(23)), + [RST_BUS_I2C0] = RESET(0x5b4, BIT(0)), + [RST_BUS_I2C1] = RESET(0x5b4, BIT(1)), + [RST_BUS_I2C2] = RESET(0x5b4, BIT(2)), + [RST_BUS_I2C3] = RESET(0x5b4, BIT(3)), + [RST_BUS_I2C4] = RESET(0x5b4, BIT(4)), [RST_BUS_UART0] = RESET(0x5b4, BIT(16)), [RST_BUS_UART1] = RESET(0x5b4, BIT(17)), [RST_BUS_UART2] = RESET(0x5b4, BIT(18)), diff --git a/drivers/clk/sunxi/clk_a83t.c b/drivers/clk/sunxi/clk_a83t.c index 880c7d75997..8c6043f51e2 100644 --- a/drivers/clk/sunxi/clk_a83t.c +++ b/drivers/clk/sunxi/clk_a83t.c @@ -8,7 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun8i-a83t-ccu.h> #include <dt-bindings/reset/sun8i-a83t-ccu.h> #include <linux/bitops.h> @@ -25,6 +25,9 @@ static struct ccu_clk_gate a83t_gates[] = { [CLK_BUS_EHCI1] = GATE(0x060, BIT(27)), [CLK_BUS_OHCI0] = GATE(0x060, BIT(29)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), + [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), + [CLK_BUS_I2C2] = GATE(0x06c, BIT(2)), [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), @@ -57,6 +60,9 @@ static struct ccu_reset a83t_resets[] = { [RST_BUS_EHCI1] = RESET(0x2c0, BIT(27)), [RST_BUS_OHCI0] = RESET(0x2c0, BIT(29)), + [RST_BUS_I2C0] = RESET(0x2d8, BIT(0)), + [RST_BUS_I2C1] = RESET(0x2d8, BIT(1)), + [RST_BUS_I2C2] = RESET(0x2d8, BIT(2)), [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), [RST_BUS_UART1] = RESET(0x2d8, BIT(17)), [RST_BUS_UART2] = RESET(0x2d8, BIT(18)), diff --git a/drivers/clk/sunxi/clk_h3.c b/drivers/clk/sunxi/clk_h3.c index f81633b92d5..59afba53eef 100644 --- a/drivers/clk/sunxi/clk_h3.c +++ b/drivers/clk/sunxi/clk_h3.c @@ -8,7 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun8i-h3-ccu.h> #include <dt-bindings/reset/sun8i-h3-ccu.h> #include <linux/bitops.h> @@ -30,6 +30,9 @@ static struct ccu_clk_gate h3_gates[] = { [CLK_BUS_OHCI2] = GATE(0x060, BIT(30)), [CLK_BUS_OHCI3] = GATE(0x060, BIT(31)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), + [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), + [CLK_BUS_I2C2] = GATE(0x06c, BIT(2)), [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), @@ -74,6 +77,9 @@ static struct ccu_reset h3_resets[] = { [RST_BUS_EPHY] = RESET(0x2c8, BIT(2)), + [RST_BUS_I2C0] = RESET(0x2d8, BIT(0)), + [RST_BUS_I2C1] = RESET(0x2d8, BIT(1)), + [RST_BUS_I2C2] = RESET(0x2d8, BIT(2)), [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), [RST_BUS_UART1] = RESET(0x2d8, BIT(17)), [RST_BUS_UART2] = RESET(0x2d8, BIT(18)), diff --git a/drivers/clk/sunxi/clk_h6.c b/drivers/clk/sunxi/clk_h6.c index df93d96b3b0..4a53788352c 100644 --- a/drivers/clk/sunxi/clk_h6.c +++ b/drivers/clk/sunxi/clk_h6.c @@ -8,7 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun50i-h6-ccu.h> #include <dt-bindings/reset/sun50i-h6-ccu.h> #include <linux/bitops.h> @@ -22,6 +22,11 @@ static struct ccu_clk_gate h6_gates[] = { [CLK_BUS_UART2] = GATE(0x90c, BIT(2)), [CLK_BUS_UART3] = GATE(0x90c, BIT(3)), + [CLK_BUS_I2C0] = GATE(0x91c, BIT(0)), + [CLK_BUS_I2C1] = GATE(0x91c, BIT(1)), + [CLK_BUS_I2C2] = GATE(0x91c, BIT(2)), + [CLK_BUS_I2C3] = GATE(0x91c, BIT(3)), + [CLK_SPI0] = GATE(0x940, BIT(31)), [CLK_SPI1] = GATE(0x944, BIT(31)), @@ -57,6 +62,11 @@ static struct ccu_reset h6_resets[] = { [RST_BUS_UART2] = RESET(0x90c, BIT(18)), [RST_BUS_UART3] = RESET(0x90c, BIT(19)), + [RST_BUS_I2C0] = RESET(0x91c, BIT(16)), + [RST_BUS_I2C1] = RESET(0x91c, BIT(17)), + [RST_BUS_I2C2] = RESET(0x91c, BIT(18)), + [RST_BUS_I2C3] = RESET(0x91c, BIT(19)), + [RST_BUS_SPI0] = RESET(0x96c, BIT(16)), [RST_BUS_SPI1] = RESET(0x96c, BIT(17)), diff --git a/drivers/clk/sunxi/clk_h616.c b/drivers/clk/sunxi/clk_h616.c index 553d7c6e550..af97d3bb9f7 100644 --- a/drivers/clk/sunxi/clk_h616.c +++ b/drivers/clk/sunxi/clk_h616.c @@ -7,7 +7,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun50i-h616-ccu.h> #include <dt-bindings/reset/sun50i-h616-ccu.h> #include <linux/bitops.h> @@ -24,6 +24,12 @@ static struct ccu_clk_gate h616_gates[] = { [CLK_BUS_UART4] = GATE(0x90c, BIT(4)), [CLK_BUS_UART5] = GATE(0x90c, BIT(5)), + [CLK_BUS_I2C0] = GATE(0x91c, BIT(0)), + [CLK_BUS_I2C1] = GATE(0x91c, BIT(1)), + [CLK_BUS_I2C2] = GATE(0x91c, BIT(2)), + [CLK_BUS_I2C3] = GATE(0x91c, BIT(3)), + [CLK_BUS_I2C4] = GATE(0x91c, BIT(4)), + [CLK_SPI0] = GATE(0x940, BIT(31)), [CLK_SPI1] = GATE(0x944, BIT(31)), @@ -68,6 +74,12 @@ static struct ccu_reset h616_resets[] = { [RST_BUS_UART4] = RESET(0x90c, BIT(20)), [RST_BUS_UART5] = RESET(0x90c, BIT(21)), + [RST_BUS_I2C0] = RESET(0x91c, BIT(16)), + [RST_BUS_I2C1] = RESET(0x91c, BIT(17)), + [RST_BUS_I2C2] = RESET(0x91c, BIT(18)), + [RST_BUS_I2C3] = RESET(0x91c, BIT(19)), + [RST_BUS_I2C4] = RESET(0x91c, BIT(20)), + [RST_BUS_SPI0] = RESET(0x96c, BIT(16)), [RST_BUS_SPI1] = RESET(0x96c, BIT(17)), diff --git a/drivers/clk/sunxi/clk_h6_r.c b/drivers/clk/sunxi/clk_h6_r.c new file mode 100644 index 00000000000..b9e527e16ac --- /dev/null +++ b/drivers/clk/sunxi/clk_h6_r.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +/* + * Copyright (C) Samuel Holland <samuel@sholland.org> + */ + +#include <clk-uclass.h> +#include <dm.h> +#include <clk/sunxi.h> +#include <dt-bindings/clock/sun50i-h6-r-ccu.h> +#include <dt-bindings/reset/sun50i-h6-r-ccu.h> +#include <linux/bitops.h> + +static struct ccu_clk_gate h6_r_gates[] = { + [CLK_R_APB1_TIMER] = GATE(0x11c, BIT(0)), + [CLK_R_APB1_TWD] = GATE(0x12c, BIT(0)), + [CLK_R_APB1_PWM] = GATE(0x13c, BIT(0)), + [CLK_R_APB2_UART] = GATE(0x18c, BIT(0)), + [CLK_R_APB2_I2C] = GATE(0x19c, BIT(0)), + [CLK_R_APB2_RSB] = GATE(0x1bc, BIT(0)), + [CLK_R_APB1_IR] = GATE(0x1cc, BIT(0)), + [CLK_R_APB1_W1] = GATE(0x1ec, BIT(0)), +}; + +static struct ccu_reset h6_r_resets[] = { + [RST_R_APB1_TIMER] = RESET(0x11c, BIT(16)), + [RST_R_APB1_TWD] = RESET(0x12c, BIT(16)), + [RST_R_APB1_PWM] = RESET(0x13c, BIT(16)), + [RST_R_APB2_UART] = RESET(0x18c, BIT(16)), + [RST_R_APB2_I2C] = RESET(0x19c, BIT(16)), + [RST_R_APB2_RSB] = RESET(0x1bc, BIT(16)), + [RST_R_APB1_IR] = RESET(0x1cc, BIT(16)), + [RST_R_APB1_W1] = RESET(0x1ec, BIT(16)), +}; + +static const struct ccu_desc h6_r_ccu_desc = { + .gates = h6_r_gates, + .resets = h6_r_resets, +}; + +static int h6_r_clk_bind(struct udevice *dev) +{ + return sunxi_reset_bind(dev, ARRAY_SIZE(h6_r_resets)); +} + +static const struct udevice_id h6_r_clk_ids[] = { + { .compatible = "allwinner,sun50i-h6-r-ccu", + .data = (ulong)&h6_r_ccu_desc }, + { .compatible = "allwinner,sun50i-h616-r-ccu", + .data = (ulong)&h6_r_ccu_desc }, + { } +}; + +U_BOOT_DRIVER(clk_sun6i_h6_r) = { + .name = "sun6i_h6_r_ccu", + .id = UCLASS_CLK, + .of_match = h6_r_clk_ids, + .priv_auto = sizeof(struct ccu_priv), + .ops = &sunxi_clk_ops, + .probe = sunxi_clk_probe, + .bind = h6_r_clk_bind, +}; diff --git a/drivers/clk/sunxi/clk_r40.c b/drivers/clk/sunxi/clk_r40.c index ee1e86d22eb..4d5b69a9765 100644 --- a/drivers/clk/sunxi/clk_r40.c +++ b/drivers/clk/sunxi/clk_r40.c @@ -8,7 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun8i-r40-ccu.h> #include <dt-bindings/reset/sun8i-r40-ccu.h> #include <linux/bitops.h> @@ -32,6 +32,11 @@ static struct ccu_clk_gate r40_gates[] = { [CLK_BUS_GMAC] = GATE(0x064, BIT(17)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), + [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), + [CLK_BUS_I2C2] = GATE(0x06c, BIT(2)), + [CLK_BUS_I2C3] = GATE(0x06c, BIT(3)), + [CLK_BUS_I2C4] = GATE(0x06c, BIT(15)), [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), @@ -77,6 +82,11 @@ static struct ccu_reset r40_resets[] = { [RST_BUS_GMAC] = RESET(0x2c4, BIT(17)), + [RST_BUS_I2C0] = RESET(0x2d8, BIT(0)), + [RST_BUS_I2C1] = RESET(0x2d8, BIT(1)), + [RST_BUS_I2C2] = RESET(0x2d8, BIT(2)), + [RST_BUS_I2C3] = RESET(0x2d8, BIT(3)), + [RST_BUS_I2C4] = RESET(0x2d8, BIT(15)), [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), [RST_BUS_UART1] = RESET(0x2d8, BIT(17)), [RST_BUS_UART2] = RESET(0x2d8, BIT(18)), diff --git a/drivers/clk/sunxi/clk_sunxi.c b/drivers/clk/sunxi/clk_sunxi.c index 41934cd826e..9673b58a492 100644 --- a/drivers/clk/sunxi/clk_sunxi.c +++ b/drivers/clk/sunxi/clk_sunxi.c @@ -11,7 +11,7 @@ #include <log.h> #include <reset.h> #include <asm/io.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <linux/bitops.h> #include <linux/log2.h> diff --git a/drivers/clk/sunxi/clk_v3s.c b/drivers/clk/sunxi/clk_v3s.c index 29622199fdc..cce5c658ca0 100644 --- a/drivers/clk/sunxi/clk_v3s.c +++ b/drivers/clk/sunxi/clk_v3s.c @@ -8,7 +8,7 @@ #include <clk-uclass.h> #include <dm.h> #include <errno.h> -#include <asm/arch/ccu.h> +#include <clk/sunxi.h> #include <dt-bindings/clock/sun8i-v3s-ccu.h> #include <dt-bindings/reset/sun8i-v3s-ccu.h> #include <linux/bitops.h> @@ -20,6 +20,8 @@ static struct ccu_clk_gate v3s_gates[] = { [CLK_BUS_SPI0] = GATE(0x060, BIT(20)), [CLK_BUS_OTG] = GATE(0x060, BIT(24)), + [CLK_BUS_I2C0] = GATE(0x06c, BIT(0)), + [CLK_BUS_I2C1] = GATE(0x06c, BIT(1)), [CLK_BUS_UART0] = GATE(0x06c, BIT(16)), [CLK_BUS_UART1] = GATE(0x06c, BIT(17)), [CLK_BUS_UART2] = GATE(0x06c, BIT(18)), @@ -38,6 +40,8 @@ static struct ccu_reset v3s_resets[] = { [RST_BUS_SPI0] = RESET(0x2c0, BIT(20)), [RST_BUS_OTG] = RESET(0x2c0, BIT(24)), + [RST_BUS_I2C0] = RESET(0x2d8, BIT(0)), + [RST_BUS_I2C1] = RESET(0x2d8, BIT(1)), [RST_BUS_UART0] = RESET(0x2d8, BIT(16)), [RST_BUS_UART1] = RESET(0x2d8, BIT(17)), [RST_BUS_UART2] = RESET(0x2d8, BIT(18)), diff --git a/drivers/clk/ti/clk-am3-dpll.c b/drivers/clk/ti/clk-am3-dpll.c index 916d3080340..398a011a5ce 100644 --- a/drivers/clk/ti/clk-am3-dpll.c +++ b/drivers/clk/ti/clk-am3-dpll.c @@ -27,11 +27,17 @@ struct clk_ti_am3_dpll_priv { struct clk_ti_reg clkmode_reg; struct clk_ti_reg idlest_reg; struct clk_ti_reg clksel_reg; + struct clk_ti_reg ssc_deltam_reg; + struct clk_ti_reg ssc_modfreq_reg; struct clk clk_bypass; struct clk clk_ref; u16 last_rounded_mult; u8 last_rounded_div; + u8 min_div; ulong max_rate; + u32 ssc_modfreq; + u32 ssc_deltam; + bool ssc_downspread; }; static ulong clk_ti_am3_dpll_round_rate(struct clk *clk, ulong rate) @@ -51,7 +57,7 @@ static ulong clk_ti_am3_dpll_round_rate(struct clk *clk, ulong rate) err = rate; err_min = rate; ref_rate = clk_get_rate(&priv->clk_ref); - for (d = 1; err_min && d <= 128; d++) { + for (d = priv->min_div; err_min && d <= 128; d++) { for (m = 2; m <= 2047; m++) { r = (ref_rate * m) / d; err = abs(r - rate); @@ -71,8 +77,8 @@ static ulong clk_ti_am3_dpll_round_rate(struct clk *clk, ulong rate) priv->last_rounded_mult = mult; priv->last_rounded_div = div; - dev_dbg(clk->dev, "rate=%ld, best_rate=%ld, mult=%d, div=%d\n", rate, - ret, mult, div); + dev_dbg(clk->dev, "rate=%ld, min-div: %d, best_rate=%ld, mult=%d, div=%d\n", + rate, priv->min_div, ret, mult, div); return ret; } @@ -107,6 +113,96 @@ static int clk_ti_am3_dpll_state(struct clk *clk, u8 state) return 0; } +/** + * clk_ti_am3_dpll_ssc_program - set spread-spectrum clocking registers + * @clk: struct clk * of DPLL to set + * + * Enable the DPLL spread spectrum clocking if frequency modulation and + * frequency spreading have been set, otherwise disable it. + */ +static void clk_ti_am3_dpll_ssc_program(struct clk *clk) +{ + struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev); + unsigned long ref_rate; + u32 v, ctrl, mod_freq_divider, exponent, mantissa; + u32 deltam_step, deltam_ceil; + + ctrl = clk_ti_readl(&priv->clkmode_reg); + + if (priv->ssc_modfreq && priv->ssc_deltam) { + ctrl |= CM_CLKMODE_DPLL_SSC_EN_MASK; + + if (priv->ssc_downspread) + ctrl |= CM_CLKMODE_DPLL_SSC_DOWNSPREAD_MASK; + else + ctrl &= ~CM_CLKMODE_DPLL_SSC_DOWNSPREAD_MASK; + + ref_rate = clk_get_rate(&priv->clk_ref); + mod_freq_divider = + (ref_rate / priv->last_rounded_div) / (4 * priv->ssc_modfreq); + if (priv->ssc_modfreq > (ref_rate / 70)) + dev_warn(clk->dev, + "clock: SSC modulation frequency of DPLL %s greater than %ld\n", + clk->dev->name, ref_rate / 70); + + exponent = 0; + mantissa = mod_freq_divider; + while ((mantissa > 127) && (exponent < 7)) { + exponent++; + mantissa /= 2; + } + if (mantissa > 127) + mantissa = 127; + + v = clk_ti_readl(&priv->ssc_modfreq_reg); + v &= ~(CM_SSC_MODFREQ_DPLL_MANT_MASK | CM_SSC_MODFREQ_DPLL_EXP_MASK); + v |= mantissa << __ffs(CM_SSC_MODFREQ_DPLL_MANT_MASK); + v |= exponent << __ffs(CM_SSC_MODFREQ_DPLL_EXP_MASK); + clk_ti_writel(v, &priv->ssc_modfreq_reg); + dev_dbg(clk->dev, + "mod_freq_divider: %u, exponent: %u, mantissa: %u, modfreq_reg: 0x%x\n", + mod_freq_divider, exponent, mantissa, v); + + deltam_step = priv->last_rounded_mult * priv->ssc_deltam; + deltam_step /= 10; + if (priv->ssc_downspread) + deltam_step /= 2; + + deltam_step <<= __ffs(CM_SSC_DELTAM_DPLL_INT_MASK); + deltam_step /= 100; + deltam_step /= mod_freq_divider; + if (deltam_step > 0xFFFFF) + deltam_step = 0xFFFFF; + + deltam_ceil = (deltam_step & CM_SSC_DELTAM_DPLL_INT_MASK) >> + __ffs(CM_SSC_DELTAM_DPLL_INT_MASK); + if (deltam_step & CM_SSC_DELTAM_DPLL_FRAC_MASK) + deltam_ceil++; + + if ((priv->ssc_downspread && + ((priv->last_rounded_mult - (2 * deltam_ceil)) < 20 || + priv->last_rounded_mult > 2045)) || + ((priv->last_rounded_mult - deltam_ceil) < 20 || + (priv->last_rounded_mult + deltam_ceil) > 2045)) + dev_warn(clk->dev, + "clock: SSC multiplier of DPLL %s is out of range\n", + clk->dev->name); + + v = clk_ti_readl(&priv->ssc_deltam_reg); + v &= ~(CM_SSC_DELTAM_DPLL_INT_MASK | CM_SSC_DELTAM_DPLL_FRAC_MASK); + v |= deltam_step << __ffs(CM_SSC_DELTAM_DPLL_INT_MASK | + CM_SSC_DELTAM_DPLL_FRAC_MASK); + clk_ti_writel(v, &priv->ssc_deltam_reg); + dev_dbg(clk->dev, + "deltam_step: %u, deltam_ceil: %u, deltam_reg: 0x%x\n", + deltam_step, deltam_ceil, v); + } else { + ctrl &= ~CM_CLKMODE_DPLL_SSC_EN_MASK; + } + + clk_ti_writel(ctrl, &priv->clkmode_reg); +} + static ulong clk_ti_am3_dpll_set_rate(struct clk *clk, ulong rate) { struct clk_ti_am3_dpll_priv *priv = dev_get_priv(clk->dev); @@ -136,6 +232,8 @@ static ulong clk_ti_am3_dpll_set_rate(struct clk *clk, ulong rate) clk_ti_writel(v, &priv->clksel_reg); + clk_ti_am3_dpll_ssc_program(clk); + /* lock dpll */ clk_ti_am3_dpll_clken(priv, DPLL_EN_LOCK); @@ -229,6 +327,7 @@ static int clk_ti_am3_dpll_of_to_plat(struct udevice *dev) struct clk_ti_am3_dpll_priv *priv = dev_get_priv(dev); struct clk_ti_am3_dpll_drv_data *data = (struct clk_ti_am3_dpll_drv_data *)dev_get_driver_data(dev); + u32 min_div; int err; priv->max_rate = data->max_rate; @@ -251,6 +350,32 @@ static int clk_ti_am3_dpll_of_to_plat(struct udevice *dev) return err; } + err = clk_ti_get_reg_addr(dev, 3, &priv->ssc_deltam_reg); + if (err) { + dev_err(dev, "failed to get SSC deltam register\n"); + return err; + } + + err = clk_ti_get_reg_addr(dev, 4, &priv->ssc_modfreq_reg); + if (err) { + dev_err(dev, "failed to get SSC modfreq register\n"); + return err; + } + + if (dev_read_u32(dev, "ti,ssc-modfreq-hz", &priv->ssc_modfreq)) + priv->ssc_modfreq = 0; + + if (dev_read_u32(dev, "ti,ssc-deltam", &priv->ssc_deltam)) + priv->ssc_deltam = 0; + + priv->ssc_downspread = dev_read_bool(dev, "ti,ssc-downspread"); + + if (dev_read_u32(dev, "ti,min-div", &min_div) || min_div == 0 || + min_div > 128) + priv->min_div = 1; + else + priv->min_div = min_div; + return 0; } diff --git a/drivers/core/device.c b/drivers/core/device.c index 42ba2dce465..d7a778a2413 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -1135,7 +1135,7 @@ int dev_enable_by_path(const char *path) if (ret) return ret; - return lists_bind_fdt(parent, node, NULL, false); + return lists_bind_fdt(parent, node, NULL, NULL, false); } #endif diff --git a/drivers/core/fdtaddr.c b/drivers/core/fdtaddr.c index 6dfda207726..c3a50a2b0c1 100644 --- a/drivers/core/fdtaddr.c +++ b/drivers/core/fdtaddr.c @@ -93,6 +93,13 @@ fdt_addr_t devfdt_get_addr_index(const struct udevice *dev, int index) #endif } +void *devfdt_get_addr_index_ptr(const struct udevice *dev, int index) +{ + fdt_addr_t addr = devfdt_get_addr_index(dev, index); + + return (addr == FDT_ADDR_T_NONE) ? NULL : (void *)(uintptr_t)addr; +} + fdt_addr_t devfdt_get_addr_size_index(const struct udevice *dev, int index, fdt_size_t *size) { @@ -155,9 +162,7 @@ fdt_addr_t devfdt_get_addr(const struct udevice *dev) void *devfdt_get_addr_ptr(const struct udevice *dev) { - fdt_addr_t addr = devfdt_get_addr_index(dev, 0); - - return (addr == FDT_ADDR_T_NONE) ? NULL : (void *)(uintptr_t)addr; + return devfdt_get_addr_index_ptr(dev, 0); } void *devfdt_remap_addr_index(const struct udevice *dev, int index) diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 350b9d32687..5d4f2ea0e3a 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -182,7 +182,7 @@ static int driver_check_compatible(const struct udevice_id *of_match, } int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, - bool pre_reloc_only) + struct driver *drv, bool pre_reloc_only) { struct driver *driver = ll_entry_start(struct driver, driver); const int n_ents = ll_entry_count(struct driver, driver); @@ -225,6 +225,8 @@ int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp, for (entry = driver; entry != driver + n_ents; entry++) { ret = driver_check_compatible(entry->of_match, &id, compat); + if ((drv) && (drv == entry)) + break; if (!ret) break; } diff --git a/drivers/core/root.c b/drivers/core/root.c index fecdcb5b308..26b8195faa3 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -276,7 +276,7 @@ static int dm_scan_fdt_node(struct udevice *parent, ofnode parent_node, pr_debug(" - ignoring disabled device\n"); continue; } - err = lists_bind_fdt(parent, node, NULL, pre_reloc_only); + err = lists_bind_fdt(parent, node, NULL, NULL, pre_reloc_only); if (err && !ret) { ret = err; debug("%s: ret=%d\n", node_name, ret); diff --git a/drivers/fastboot/fb_mmc.c b/drivers/fastboot/fb_mmc.c index cbb3f7b1dea..2738dc836e1 100644 --- a/drivers/fastboot/fb_mmc.c +++ b/drivers/fastboot/fb_mmc.c @@ -40,7 +40,7 @@ static int raw_part_get_info_by_name(struct blk_desc *dev_desc, /* check for raw partition descriptor */ strcpy(env_desc_name, "fastboot_raw_partition_"); - strlcat(env_desc_name, name, PART_NAME_LEN); + strlcat(env_desc_name, name, sizeof(env_desc_name)); raw_part_desc = strdup(env_get(env_desc_name)); if (raw_part_desc == NULL) return -ENODEV; @@ -114,7 +114,7 @@ static int part_get_info_by_name_or_alias(struct blk_desc **dev_desc, /* check for alias */ strcpy(env_alias_name, "fastboot_partition_alias_"); - strlcat(env_alias_name, name, PART_NAME_LEN); + strlcat(env_alias_name, name, sizeof(env_alias_name)); aliased_part_name = env_get(env_alias_name); if (aliased_part_name != NULL) ret = do_get_part_info(dev_desc, aliased_part_name, diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index f0439e24178..40abc33772e 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -183,6 +183,14 @@ config LPC32XX_GPIO help Support for the LPC32XX GPIO driver. +config MAX7320_GPIO + bool "MAX7320 I2C GPIO Expander driver" + depends on DM_GPIO && DM_I2C + help + Support for MAX7320 I2C 8/16-bit GPIO expander. + original maxim device has 8 push/pull outputs, + some clones offers 16bit. + config MCP230XX_GPIO bool "MCP230XX GPIO driver" depends on DM diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index a9dc546a20b..3c851b38c7c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -68,3 +68,4 @@ obj-$(CONFIG_MSCC_SGPIO) += mscc_sgpio.o obj-$(CONFIG_NX_GPIO) += nx_gpio.o obj-$(CONFIG_SIFIVE_GPIO) += sifive-gpio.o obj-$(CONFIG_NOMADIK_GPIO) += nmk_gpio.o +obj-$(CONFIG_MAX7320_GPIO) += max7320_gpio.o diff --git a/drivers/gpio/axp_gpio.c b/drivers/gpio/axp_gpio.c index 73058cf40b4..35585dc8ac9 100644 --- a/drivers/gpio/axp_gpio.c +++ b/drivers/gpio/axp_gpio.c @@ -6,7 +6,6 @@ */ #include <common.h> -#include <asm/arch/gpio.h> #include <asm/arch/pmic_bus.h> #include <asm/gpio.h> #include <axp_pmic.h> diff --git a/drivers/gpio/max7320_gpio.c b/drivers/gpio/max7320_gpio.c new file mode 100644 index 00000000000..647aed907b4 --- /dev/null +++ b/drivers/gpio/max7320_gpio.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * max7320 I2C GPIO EXPANDER DRIVER + * + * Copyright (C) 2021 Hannes Schmelzer <oe5hpm@oevsv.at> + * B&R Industrial Automation GmbH - http://www.br-automation.com + * + */ + +#include <common.h> +#include <dm.h> +#include <i2c.h> +#include <asm-generic/gpio.h> +#include <linux/bitops.h> + +struct max7320_chip { + u32 outreg; +}; + +static int max7320_direction_output(struct udevice *dev, + unsigned int offset, int value) +{ + struct max7320_chip *plat = dev_get_plat(dev); + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + struct dm_i2c_chip *chip = dev_get_parent_plat(dev); + + int ret; + + if (value) + plat->outreg |= BIT(offset); + else + plat->outreg &= ~BIT(offset); + + ret = dm_i2c_write(dev, + plat->outreg & 0xff, + (uint8_t *)&plat->outreg + 1, + uc_priv->gpio_count > 8 ? 1 : 0); + if (ret) + printf("%s i2c write failed to addr %x\n", __func__, + chip->chip_addr); + + return ret; +} + +static int max7320_get_value(struct udevice *dev, unsigned int offset) +{ + struct max7320_chip *plat = dev_get_plat(dev); + + return (plat->outreg >> offset) & 0x1; +} + +static int max7320_set_value(struct udevice *dev, unsigned int offset, + int value) +{ + return max7320_direction_output(dev, offset, value); +} + +static int max7320_get_function(struct udevice *dev, unsigned int offset) +{ + return GPIOF_OUTPUT; +} + +static int max7320_ofdata_plat(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + uc_priv->gpio_count = dev_read_u32_default(dev, "ngpios", 8); + if (uc_priv->gpio_count > 16) { + printf("%s: max7320 doesn't support more than 16 gpios!", + __func__); + return -EINVAL; + } + + uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), + "gpio-bank-name", NULL); + if (!uc_priv->bank_name) + uc_priv->bank_name = fdt_get_name(gd->fdt_blob, + dev_of_offset(dev), NULL); + + return 0; +} + +static int max7320_gpio_probe(struct udevice *dev) +{ + struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + debug("%s GPIO controller with %d gpios probed\n", + uc_priv->bank_name, uc_priv->gpio_count); + + return 0; +} + +static const struct dm_gpio_ops max7320_gpio_ops = { + .direction_output = max7320_direction_output, + .set_value = max7320_set_value, + .get_value = max7320_get_value, + .get_function = max7320_get_function, +}; + +static const struct udevice_id max7320_gpio_ids[] = { + { .compatible = "maxim,max7320" }, + { } +}; + +U_BOOT_DRIVER(gpio_max7320) = { + .name = "gpio_max7320", + .id = UCLASS_GPIO, + .ops = &max7320_gpio_ops, + .of_match = max7320_gpio_ids, + .of_to_plat = max7320_ofdata_plat, + .probe = max7320_gpio_probe, + .plat_auto = sizeof(struct max7320_chip), +}; diff --git a/drivers/gpio/sifive-gpio.c b/drivers/gpio/sifive-gpio.c index abd1f629b9b..151f484e8fd 100644 --- a/drivers/gpio/sifive-gpio.c +++ b/drivers/gpio/sifive-gpio.c @@ -157,13 +157,11 @@ static const struct dm_gpio_ops sifive_gpio_ops = { static int sifive_gpio_of_to_plat(struct udevice *dev) { struct sifive_gpio_plat *plat = dev_get_plat(dev); - fdt_addr_t addr; - addr = dev_read_addr(dev); - if (addr == FDT_ADDR_T_NONE) + plat->base = dev_read_addr_ptr(dev); + if (!plat->base) return -EINVAL; - plat->base = (void *)addr; return 0; } diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 24cb604e3e3..cdbc40d48fd 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -14,14 +14,11 @@ #include <errno.h> #include <fdtdec.h> #include <malloc.h> -#include <asm/arch/gpio.h> #include <asm/io.h> #include <asm/gpio.h> #include <dm/device-internal.h> #include <dt-bindings/gpio/gpio.h> -#define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR - struct sunxi_gpio_plat { struct sunxi_gpio *regs; const char *bank_name; /* Name of bank, e.g. "B" */ @@ -118,20 +115,6 @@ int sunxi_name_to_gpio(const char *name) } #endif /* DM_GPIO */ -int sunxi_name_to_gpio_bank(const char *name) -{ - int group = 0; - - if (*name == 'P' || *name == 'p') - name++; - if (*name >= 'A') { - group = *name - (*name > 'a' ? 'a' : 'A'); - return group; - } - - return -1; -} - #if CONFIG_IS_ENABLED(DM_GPIO) /* TODO(sjg@chromium.org): Remove this function and use device tree */ int sunxi_name_to_gpio(const char *name) diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 57cac4483f0..66bd6fe2f34 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -575,6 +575,22 @@ config SYS_I2C_STM32F7 _ Optional clock stretching _ Software reset +config SYS_I2C_SUN6I_P2WI + bool "Allwinner sun6i P2WI controller" + depends on ARCH_SUNXI + help + Support for the P2WI (Push/Pull 2 Wire Interface) controller embedded + in the Allwinner A31 and A31s SOCs. This interface is used to connect + to specific devices like the X-Powers AXP221 PMIC. + +config SYS_I2C_SUN8I_RSB + bool "Allwinner sun8i Reduced Serial Bus controller" + depends on ARCH_SUNXI + help + Support for Allwinner's Reduced Serial Bus (RSB) controller. This + controller is responsible for communicating with various RSB based + devices, such as X-Powers AXPxxx PMICs and AC100/AC200 CODEC ICs. + config SYS_I2C_SYNQUACER bool "Socionext SynQuacer I2C controller" depends on ARCH_SYNQUACER && DM_I2C diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 67841bf3e02..916427452a5 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -43,6 +43,8 @@ obj-$(CONFIG_SYS_I2C_SANDBOX) += sandbox_i2c.o i2c-emul-uclass.o obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o obj-$(CONFIG_SYS_I2C_STM32F7) += stm32f7_i2c.o +obj-$(CONFIG_SYS_I2C_SUN6I_P2WI) += sun6i_p2wi.o +obj-$(CONFIG_SYS_I2C_SUN8I_RSB) += sun8i_rsb.o obj-$(CONFIG_SYS_I2C_SYNQUACER) += synquacer_i2c.o obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o diff --git a/drivers/i2c/ocores_i2c.c b/drivers/i2c/ocores_i2c.c index f129ec3818c..3b19ba78fa3 100644 --- a/drivers/i2c/ocores_i2c.c +++ b/drivers/i2c/ocores_i2c.c @@ -516,7 +516,7 @@ static int ocores_i2c_probe(struct udevice *dev) u32 clock_frequency_khz; int ret; - bus->base = (void __iomem *)devfdt_get_addr(dev); + bus->base = dev_read_addr_ptr(dev); if (dev_read_u32(dev, "reg-shift", &bus->reg_shift)) { /* no 'reg-shift', check for deprecated 'regstep' */ diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c index 7b04a09de0b..c6ae65badb7 100644 --- a/drivers/i2c/stm32f7_i2c.c +++ b/drivers/i2c/stm32f7_i2c.c @@ -45,6 +45,8 @@ struct stm32_i2c_regs { /* STM32 I2C control 1 */ #define STM32_I2C_CR1_ANFOFF BIT(12) +#define STM32_I2C_CR1_DNF_MASK GENMASK(11, 8) +#define STM32_I2C_CR1_DNF(n) (((n) & 0xf) << 8) #define STM32_I2C_CR1_ERRIE BIT(7) #define STM32_I2C_CR1_TCIE BIT(6) #define STM32_I2C_CR1_STOPIE BIT(5) @@ -105,10 +107,8 @@ struct stm32_i2c_regs { #define STM32_I2C_MAX_LEN 0xff -#define STM32_I2C_DNF_DEFAULT 0 -#define STM32_I2C_DNF_MAX 16 +#define STM32_I2C_DNF_MAX 15 -#define STM32_I2C_ANALOG_FILTER_ENABLE 1 #define STM32_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */ #define STM32_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */ @@ -156,9 +156,8 @@ struct stm32_i2c_spec { * @clock_src: I2C clock source frequency (Hz) * @rise_time: Rise time (ns) * @fall_time: Fall time (ns) - * @dnf: Digital filter coefficient (0-16) + * @dnf: value of digital filter to apply * @analog_filter: Analog filter delay (On/Off) - * @fmp_clr_offset: Fast Mode Plus clear register offset from set register */ struct stm32_i2c_setup { u32 speed_freq; @@ -167,6 +166,13 @@ struct stm32_i2c_setup { u32 fall_time; u8 dnf; bool analog_filter; +}; + +/** + * struct stm32_i2c_data - driver data for I2C configuration by compatible + * @fmp_clr_offset: Fast Mode Plus clear register offset from set register + */ +struct stm32_i2c_data { u32 fmp_clr_offset; }; @@ -197,16 +203,18 @@ struct stm32_i2c_timings { * @regmap_sreg: register address for setting Fast Mode Plus bits * @regmap_creg: register address for clearing Fast Mode Plus bits * @regmap_mask: mask for Fast Mode Plus bits + * @dnf_dt: value of digital filter requested via dt */ struct stm32_i2c_priv { struct stm32_i2c_regs *regs; struct clk clk; - struct stm32_i2c_setup *setup; + struct stm32_i2c_setup setup; u32 speed; struct regmap *regmap; u32 regmap_sreg; u32 regmap_creg; u32 regmap_mask; + u32 dnf_dt; }; static const struct stm32_i2c_spec i2c_specs[] = { @@ -251,18 +259,11 @@ static const struct stm32_i2c_spec i2c_specs[] = { }, }; -static const struct stm32_i2c_setup stm32f7_setup = { - .rise_time = STM32_I2C_RISE_TIME_DEFAULT, - .fall_time = STM32_I2C_FALL_TIME_DEFAULT, - .dnf = STM32_I2C_DNF_DEFAULT, - .analog_filter = STM32_I2C_ANALOG_FILTER_ENABLE, +static const struct stm32_i2c_data stm32f7_data = { + .fmp_clr_offset = 0x00, }; -static const struct stm32_i2c_setup stm32mp15_setup = { - .rise_time = STM32_I2C_RISE_TIME_DEFAULT, - .fall_time = STM32_I2C_FALL_TIME_DEFAULT, - .dnf = STM32_I2C_DNF_DEFAULT, - .analog_filter = STM32_I2C_ANALOG_FILTER_ENABLE, +static const struct stm32_i2c_data stm32mp15_data = { .fmp_clr_offset = 0x40, }; @@ -506,14 +507,13 @@ static int stm32_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, return 0; } -static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, +static int stm32_i2c_compute_solutions(u32 i2cclk, + struct stm32_i2c_setup *setup, const struct stm32_i2c_spec *specs, struct list_head *solutions) { struct stm32_i2c_timings *v; u32 p_prev = STM32_PRESC_MAX; - u32 i2cclk = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC, - setup->clock_src); u32 af_delay_min, af_delay_max; u16 p, l, a; int sdadel_min, sdadel_max, scldel_min; @@ -581,7 +581,8 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup, return ret; } -static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, +static int stm32_i2c_choose_solution(u32 i2cclk, + struct stm32_i2c_setup *setup, const struct stm32_i2c_spec *specs, struct list_head *solutions, struct stm32_i2c_timings *s) @@ -590,8 +591,6 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup, u32 i2cbus = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC, setup->speed_freq); u32 clk_error_prev = i2cbus; - u32 i2cclk = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC, - setup->clock_src); u32 clk_min, clk_max; u32 af_delay_min; u32 dnf_delay; @@ -678,12 +677,13 @@ static const struct stm32_i2c_spec *get_specs(u32 rate) } static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, - struct stm32_i2c_setup *setup, struct stm32_i2c_timings *output) { + struct stm32_i2c_setup *setup = &i2c_priv->setup; const struct stm32_i2c_spec *specs; struct stm32_i2c_timings *v, *_v; struct list_head solutions; + u32 i2cclk = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC, setup->clock_src); int ret; specs = get_specs(setup->speed_freq); @@ -701,6 +701,8 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, return -EINVAL; } + /* Analog and Digital Filters */ + setup->dnf = DIV_ROUND_CLOSEST(i2c_priv->dnf_dt, i2cclk); if (setup->dnf > STM32_I2C_DNF_MAX) { log_err("DNF out of bound %d/%d\n", setup->dnf, STM32_I2C_DNF_MAX); @@ -708,11 +710,11 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, } INIT_LIST_HEAD(&solutions); - ret = stm32_i2c_compute_solutions(setup, specs, &solutions); + ret = stm32_i2c_compute_solutions(i2cclk, setup, specs, &solutions); if (ret) goto exit; - ret = stm32_i2c_choose_solution(setup, specs, &solutions, output); + ret = stm32_i2c_choose_solution(i2cclk, setup, specs, &solutions, output); if (ret) goto exit; @@ -745,7 +747,7 @@ static u32 get_lower_rate(u32 rate) static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, struct stm32_i2c_timings *timing) { - struct stm32_i2c_setup *setup = i2c_priv->setup; + struct stm32_i2c_setup *setup = &i2c_priv->setup; int ret = 0; setup->speed_freq = i2c_priv->speed; @@ -757,7 +759,7 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv, } do { - ret = stm32_i2c_compute_timing(i2c_priv, setup, timing); + ret = stm32_i2c_compute_timing(i2c_priv, timing); if (ret) { log_debug("failed to compute I2C timings.\n"); if (setup->speed_freq > I2C_SPEED_STANDARD_RATE) { @@ -839,10 +841,15 @@ static int stm32_i2c_hw_config(struct stm32_i2c_priv *i2c_priv) writel(timing, ®s->timingr); /* Enable I2C */ - if (i2c_priv->setup->analog_filter) + if (i2c_priv->setup.analog_filter) clrbits_le32(®s->cr1, STM32_I2C_CR1_ANFOFF); else setbits_le32(®s->cr1, STM32_I2C_CR1_ANFOFF); + + /* Program the Digital Filter */ + clrsetbits_le32(®s->cr1, STM32_I2C_CR1_DNF_MASK, + STM32_I2C_CR1_DNF(i2c_priv->setup.dnf)); + setbits_le32(®s->cr1, STM32_I2C_CR1_PE); return 0; @@ -903,21 +910,26 @@ clk_free: static int stm32_of_to_plat(struct udevice *dev) { + const struct stm32_i2c_data *data; struct stm32_i2c_priv *i2c_priv = dev_get_priv(dev); u32 rise_time, fall_time; int ret; - i2c_priv->setup = (struct stm32_i2c_setup *)dev_get_driver_data(dev); - if (!i2c_priv->setup) + data = (const struct stm32_i2c_data *)dev_get_driver_data(dev); + if (!data) return -EINVAL; - rise_time = dev_read_u32_default(dev, "i2c-scl-rising-time-ns", 0); - if (rise_time) - i2c_priv->setup->rise_time = rise_time; + rise_time = dev_read_u32_default(dev, "i2c-scl-rising-time-ns", + STM32_I2C_RISE_TIME_DEFAULT); + + fall_time = dev_read_u32_default(dev, "i2c-scl-falling-time-ns", + STM32_I2C_FALL_TIME_DEFAULT); + + i2c_priv->dnf_dt = dev_read_u32_default(dev, "i2c-digital-filter-width-ns", 0); + if (!dev_read_bool(dev, "i2c-digital-filter")) + i2c_priv->dnf_dt = 0; - fall_time = dev_read_u32_default(dev, "i2c-scl-falling-time-ns", 0); - if (fall_time) - i2c_priv->setup->fall_time = fall_time; + i2c_priv->setup.analog_filter = dev_read_bool(dev, "i2c-analog-filter"); /* Optional */ i2c_priv->regmap = syscon_regmap_lookup_by_phandle(dev, @@ -930,8 +942,7 @@ static int stm32_of_to_plat(struct udevice *dev) return ret; i2c_priv->regmap_sreg = fmp[1]; - i2c_priv->regmap_creg = fmp[1] + - i2c_priv->setup->fmp_clr_offset; + i2c_priv->regmap_creg = fmp[1] + data->fmp_clr_offset; i2c_priv->regmap_mask = fmp[2]; } @@ -944,8 +955,8 @@ static const struct dm_i2c_ops stm32_i2c_ops = { }; static const struct udevice_id stm32_i2c_of_match[] = { - { .compatible = "st,stm32f7-i2c", .data = (ulong)&stm32f7_setup }, - { .compatible = "st,stm32mp15-i2c", .data = (ulong)&stm32mp15_setup }, + { .compatible = "st,stm32f7-i2c", .data = (ulong)&stm32f7_data }, + { .compatible = "st,stm32mp15-i2c", .data = (ulong)&stm32mp15_data }, {} }; diff --git a/drivers/i2c/sun6i_p2wi.c b/drivers/i2c/sun6i_p2wi.c new file mode 100644 index 00000000000..c9e1b3fcd5f --- /dev/null +++ b/drivers/i2c/sun6i_p2wi.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Sunxi A31 Power Management Unit + * + * (C) Copyright 2013 Oliver Schinagl <oliver@schinagl.nl> + * http://linux-sunxi.org + * + * Based on sun6i sources and earlier U-Boot Allwinner A10 SPL work + * + * (C) Copyright 2006-2013 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * Berg Xing <bergxing@allwinnertech.com> + * Tom Cubie <tangliang@allwinnertech.com> + */ + +#include <axp_pmic.h> +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <i2c.h> +#include <time.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/gpio.h> +#include <asm/arch/p2wi.h> +#include <asm/arch/prcm.h> +#include <asm/arch/sys_proto.h> + +static int sun6i_p2wi_await_trans(struct sunxi_p2wi_reg *base) +{ + unsigned long tmo = timer_get_us() + 1000000; + int ret; + u8 reg; + + while (1) { + reg = readl(&base->status); + if (reg & P2WI_STAT_TRANS_ERR) { + ret = -EIO; + break; + } + if (reg & P2WI_STAT_TRANS_DONE) { + ret = 0; + break; + } + if (timer_get_us() > tmo) { + ret = -ETIME; + break; + } + } + writel(reg, &base->status); /* Clear status bits */ + + return ret; +} + +static int sun6i_p2wi_read(struct sunxi_p2wi_reg *base, const u8 addr, u8 *data) +{ + int ret; + + writel(P2WI_DATADDR_BYTE_1(addr), &base->dataddr0); + writel(P2WI_DATA_NUM_BYTES(1) | + P2WI_DATA_NUM_BYTES_READ, &base->numbytes); + writel(P2WI_STAT_TRANS_DONE, &base->status); + writel(P2WI_CTRL_TRANS_START, &base->ctrl); + + ret = sun6i_p2wi_await_trans(base); + + *data = readl(&base->data0) & P2WI_DATA_BYTE_1_MASK; + + return ret; +} + +static int sun6i_p2wi_write(struct sunxi_p2wi_reg *base, const u8 addr, u8 data) +{ + writel(P2WI_DATADDR_BYTE_1(addr), &base->dataddr0); + writel(P2WI_DATA_BYTE_1(data), &base->data0); + writel(P2WI_DATA_NUM_BYTES(1), &base->numbytes); + writel(P2WI_STAT_TRANS_DONE, &base->status); + writel(P2WI_CTRL_TRANS_START, &base->ctrl); + + return sun6i_p2wi_await_trans(base); +} + +static int sun6i_p2wi_change_to_p2wi_mode(struct sunxi_p2wi_reg *base, + u8 slave_addr, u8 ctrl_reg, + u8 init_data) +{ + unsigned long tmo = timer_get_us() + 1000000; + + writel(P2WI_PM_DEV_ADDR(slave_addr) | + P2WI_PM_CTRL_ADDR(ctrl_reg) | + P2WI_PM_INIT_DATA(init_data) | + P2WI_PM_INIT_SEND, + &base->pm); + + while ((readl(&base->pm) & P2WI_PM_INIT_SEND)) { + if (timer_get_us() > tmo) + return -ETIME; + } + + return 0; +} + +static void sun6i_p2wi_init(struct sunxi_p2wi_reg *base) +{ + /* Enable p2wi and PIO clk, and de-assert their resets */ + prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_P2WI); + + sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN6I_GPL0_R_P2WI_SCK); + sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN6I_GPL1_R_P2WI_SDA); + + /* Reset p2wi controller and set clock to CLKIN(12)/8 = 1.5 MHz */ + writel(P2WI_CTRL_RESET, &base->ctrl); + sdelay(0x100); + writel(P2WI_CC_SDA_OUT_DELAY(1) | P2WI_CC_CLK_DIV(8), + &base->cc); +} + +#if IS_ENABLED(CONFIG_AXP_PMIC_BUS) +int p2wi_read(const u8 addr, u8 *data) +{ + struct sunxi_p2wi_reg *base = (struct sunxi_p2wi_reg *)SUN6I_P2WI_BASE; + + return sun6i_p2wi_read(base, addr, data); +} + +int p2wi_write(const u8 addr, u8 data) +{ + struct sunxi_p2wi_reg *base = (struct sunxi_p2wi_reg *)SUN6I_P2WI_BASE; + + return sun6i_p2wi_write(base, addr, data); +} + +int p2wi_change_to_p2wi_mode(u8 slave_addr, u8 ctrl_reg, u8 init_data) +{ + struct sunxi_p2wi_reg *base = (struct sunxi_p2wi_reg *)SUN6I_P2WI_BASE; + + return sun6i_p2wi_change_to_p2wi_mode(base, slave_addr, ctrl_reg, + init_data); +} + +void p2wi_init(void) +{ + struct sunxi_p2wi_reg *base = (struct sunxi_p2wi_reg *)SUN6I_P2WI_BASE; + + sun6i_p2wi_init(base); +} +#endif + +#if CONFIG_IS_ENABLED(DM_I2C) +struct sun6i_p2wi_priv { + struct sunxi_p2wi_reg *base; +}; + +static int sun6i_p2wi_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) +{ + struct sun6i_p2wi_priv *priv = dev_get_priv(bus); + + /* The hardware only supports SMBus-style transfers. */ + if (nmsgs == 2 && msg[1].flags == I2C_M_RD && msg[1].len == 1) + return sun6i_p2wi_read(priv->base, + msg[0].buf[0], &msg[1].buf[0]); + + if (nmsgs == 1 && msg[0].len == 2) + return sun6i_p2wi_write(priv->base, + msg[0].buf[0], msg[0].buf[1]); + + return -EINVAL; +} + +static int sun6i_p2wi_probe_chip(struct udevice *bus, uint chip_addr, + uint chip_flags) +{ + struct sun6i_p2wi_priv *priv = dev_get_priv(bus); + + return sun6i_p2wi_change_to_p2wi_mode(priv->base, chip_addr, + AXP_PMIC_MODE_REG, + AXP_PMIC_MODE_P2WI); +} + +static int sun6i_p2wi_probe(struct udevice *bus) +{ + struct sun6i_p2wi_priv *priv = dev_get_priv(bus); + + priv->base = dev_read_addr_ptr(bus); + + sun6i_p2wi_init(priv->base); + + return 0; +} + +static int sun6i_p2wi_child_pre_probe(struct udevice *child) +{ + struct dm_i2c_chip *chip = dev_get_parent_plat(child); + + /* Ensure each transfer is for a single register. */ + chip->flags |= DM_I2C_CHIP_RD_ADDRESS | DM_I2C_CHIP_WR_ADDRESS; + + return 0; +} + +static const struct dm_i2c_ops sun6i_p2wi_ops = { + .xfer = sun6i_p2wi_xfer, + .probe_chip = sun6i_p2wi_probe_chip, +}; + +static const struct udevice_id sun6i_p2wi_ids[] = { + { .compatible = "allwinner,sun6i-a31-p2wi" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(sun6i_p2wi) = { + .name = "sun6i_p2wi", + .id = UCLASS_I2C, + .of_match = sun6i_p2wi_ids, + .probe = sun6i_p2wi_probe, + .child_pre_probe = sun6i_p2wi_child_pre_probe, + .priv_auto = sizeof(struct sun6i_p2wi_priv), + .ops = &sun6i_p2wi_ops, +}; +#endif /* CONFIG_IS_ENABLED(DM_I2C) */ diff --git a/drivers/i2c/sun8i_rsb.c b/drivers/i2c/sun8i_rsb.c new file mode 100644 index 00000000000..716b245a003 --- /dev/null +++ b/drivers/i2c/sun8i_rsb.c @@ -0,0 +1,281 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2014 Hans de Goede <hdegoede@redhat.com> + * + * Based on allwinner u-boot sources rsb code which is: + * (C) Copyright 2007-2013 + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * lixiang <lixiang@allwinnertech.com> + */ + +#include <axp_pmic.h> +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <i2c.h> +#include <time.h> +#include <asm/arch/cpu.h> +#include <asm/arch/gpio.h> +#include <asm/arch/prcm.h> +#include <asm/arch/rsb.h> + +static int sun8i_rsb_await_trans(struct sunxi_rsb_reg *base) +{ + unsigned long tmo = timer_get_us() + 1000000; + u32 stat; + int ret; + + while (1) { + stat = readl(&base->stat); + if (stat & RSB_STAT_LBSY_INT) { + ret = -EBUSY; + break; + } + if (stat & RSB_STAT_TERR_INT) { + ret = -EIO; + break; + } + if (stat & RSB_STAT_TOVER_INT) { + ret = 0; + break; + } + if (timer_get_us() > tmo) { + ret = -ETIME; + break; + } + } + writel(stat, &base->stat); /* Clear status bits */ + + return ret; +} + +static int sun8i_rsb_do_trans(struct sunxi_rsb_reg *base) +{ + setbits_le32(&base->ctrl, RSB_CTRL_START_TRANS); + + return sun8i_rsb_await_trans(base); +} + +static int sun8i_rsb_read(struct sunxi_rsb_reg *base, u16 runtime_addr, + u8 reg_addr, u8 *data) +{ + int ret; + + writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_addr), &base->devaddr); + writel(reg_addr, &base->addr); + writel(RSB_CMD_BYTE_READ, &base->cmd); + + ret = sun8i_rsb_do_trans(base); + if (ret) + return ret; + + *data = readl(&base->data) & 0xff; + + return 0; +} + +static int sun8i_rsb_write(struct sunxi_rsb_reg *base, u16 runtime_addr, + u8 reg_addr, u8 data) +{ + writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_addr), &base->devaddr); + writel(reg_addr, &base->addr); + writel(data, &base->data); + writel(RSB_CMD_BYTE_WRITE, &base->cmd); + + return sun8i_rsb_do_trans(base); +} + +static int sun8i_rsb_set_device_address(struct sunxi_rsb_reg *base, + u16 device_addr, u16 runtime_addr) +{ + writel(RSB_DEVADDR_RUNTIME_ADDR(runtime_addr) | + RSB_DEVADDR_DEVICE_ADDR(device_addr), &base->devaddr); + writel(RSB_CMD_SET_RTSADDR, &base->cmd); + + return sun8i_rsb_do_trans(base); +} + +static void sun8i_rsb_cfg_io(void) +{ +#ifdef CONFIG_MACH_SUN8I + sunxi_gpio_set_cfgpin(SUNXI_GPL(0), SUN8I_GPL_R_RSB); + sunxi_gpio_set_cfgpin(SUNXI_GPL(1), SUN8I_GPL_R_RSB); + sunxi_gpio_set_pull(SUNXI_GPL(0), 1); + sunxi_gpio_set_pull(SUNXI_GPL(1), 1); + sunxi_gpio_set_drv(SUNXI_GPL(0), 2); + sunxi_gpio_set_drv(SUNXI_GPL(1), 2); +#elif defined CONFIG_MACH_SUN9I + sunxi_gpio_set_cfgpin(SUNXI_GPN(0), SUN9I_GPN_R_RSB); + sunxi_gpio_set_cfgpin(SUNXI_GPN(1), SUN9I_GPN_R_RSB); + sunxi_gpio_set_pull(SUNXI_GPN(0), 1); + sunxi_gpio_set_pull(SUNXI_GPN(1), 1); + sunxi_gpio_set_drv(SUNXI_GPN(0), 2); + sunxi_gpio_set_drv(SUNXI_GPN(1), 2); +#else +#error unsupported MACH_SUNXI +#endif +} + +static void sun8i_rsb_set_clk(struct sunxi_rsb_reg *base) +{ + u32 div = 0; + u32 cd_odly = 0; + + /* Source is Hosc24M, set RSB clk to 3Mhz */ + div = 24000000 / 3000000 / 2 - 1; + cd_odly = div >> 1; + if (!cd_odly) + cd_odly = 1; + + writel((cd_odly << 8) | div, &base->ccr); +} + +static int sun8i_rsb_set_device_mode(struct sunxi_rsb_reg *base) +{ + unsigned long tmo = timer_get_us() + 1000000; + + writel(RSB_DMCR_DEVICE_MODE_START | RSB_DMCR_DEVICE_MODE_DATA, + &base->dmcr); + + while (readl(&base->dmcr) & RSB_DMCR_DEVICE_MODE_START) { + if (timer_get_us() > tmo) + return -ETIME; + } + + return sun8i_rsb_await_trans(base); +} + +static int sun8i_rsb_init(struct sunxi_rsb_reg *base) +{ + /* Enable RSB and PIO clk, and de-assert their resets */ + prcm_apb0_enable(PRCM_APB0_GATE_PIO | PRCM_APB0_GATE_RSB); + + /* Setup external pins */ + sun8i_rsb_cfg_io(); + + writel(RSB_CTRL_SOFT_RST, &base->ctrl); + sun8i_rsb_set_clk(base); + + return sun8i_rsb_set_device_mode(base); +} + +#if IS_ENABLED(CONFIG_AXP_PMIC_BUS) +int rsb_read(const u16 runtime_addr, const u8 reg_addr, u8 *data) +{ + struct sunxi_rsb_reg *base = (struct sunxi_rsb_reg *)SUNXI_RSB_BASE; + + return sun8i_rsb_read(base, runtime_addr, reg_addr, data); +} + +int rsb_write(const u16 runtime_addr, const u8 reg_addr, u8 data) +{ + struct sunxi_rsb_reg *base = (struct sunxi_rsb_reg *)SUNXI_RSB_BASE; + + return sun8i_rsb_write(base, runtime_addr, reg_addr, data); +} + +int rsb_set_device_address(u16 device_addr, u16 runtime_addr) +{ + struct sunxi_rsb_reg *base = (struct sunxi_rsb_reg *)SUNXI_RSB_BASE; + + return sun8i_rsb_set_device_address(base, device_addr, runtime_addr); +} + +int rsb_init(void) +{ + struct sunxi_rsb_reg *base = (struct sunxi_rsb_reg *)SUNXI_RSB_BASE; + + return sun8i_rsb_init(base); +} +#endif + +#if CONFIG_IS_ENABLED(DM_I2C) +struct sun8i_rsb_priv { + struct sunxi_rsb_reg *base; +}; + +/* + * The mapping from hardware address to runtime address is fixed, and shared + * among all RSB drivers. See the comment in drivers/bus/sunxi-rsb.c in Linux. + */ +static int sun8i_rsb_get_runtime_address(u16 device_addr) +{ + if (device_addr == AXP_PMIC_PRI_DEVICE_ADDR) + return AXP_PMIC_PRI_RUNTIME_ADDR; + if (device_addr == AXP_PMIC_SEC_DEVICE_ADDR) + return AXP_PMIC_SEC_RUNTIME_ADDR; + + return -ENXIO; +} + +static int sun8i_rsb_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs) +{ + int runtime_addr = sun8i_rsb_get_runtime_address(msg->addr); + struct sun8i_rsb_priv *priv = dev_get_priv(bus); + + if (runtime_addr < 0) + return runtime_addr; + + /* The hardware only supports SMBus-style transfers. */ + if (nmsgs == 2 && msg[1].flags == I2C_M_RD && msg[1].len == 1) + return sun8i_rsb_read(priv->base, runtime_addr, + msg[0].buf[0], &msg[1].buf[0]); + + if (nmsgs == 1 && msg[0].len == 2) + return sun8i_rsb_write(priv->base, runtime_addr, + msg[0].buf[0], msg[0].buf[1]); + + return -EINVAL; +} + +static int sun8i_rsb_probe_chip(struct udevice *bus, uint chip_addr, + uint chip_flags) +{ + int runtime_addr = sun8i_rsb_get_runtime_address(chip_addr); + struct sun8i_rsb_priv *priv = dev_get_priv(bus); + + if (runtime_addr < 0) + return runtime_addr; + + return sun8i_rsb_set_device_address(priv->base, chip_addr, runtime_addr); +} + +static int sun8i_rsb_probe(struct udevice *bus) +{ + struct sun8i_rsb_priv *priv = dev_get_priv(bus); + + priv->base = dev_read_addr_ptr(bus); + + return sun8i_rsb_init(priv->base); +} + +static int sun8i_rsb_child_pre_probe(struct udevice *child) +{ + struct dm_i2c_chip *chip = dev_get_parent_plat(child); + + /* Ensure each transfer is for a single register. */ + chip->flags |= DM_I2C_CHIP_RD_ADDRESS | DM_I2C_CHIP_WR_ADDRESS; + + return 0; +} + +static const struct dm_i2c_ops sun8i_rsb_ops = { + .xfer = sun8i_rsb_xfer, + .probe_chip = sun8i_rsb_probe_chip, +}; + +static const struct udevice_id sun8i_rsb_ids[] = { + { .compatible = "allwinner,sun8i-a23-rsb" }, + { /* sentinel */ } +}; + +U_BOOT_DRIVER(sun8i_rsb) = { + .name = "sun8i_rsb", + .id = UCLASS_I2C, + .of_match = sun8i_rsb_ids, + .probe = sun8i_rsb_probe, + .child_pre_probe = sun8i_rsb_child_pre_probe, + .priv_auto = sizeof(struct sun8i_rsb_priv), + .ops = &sun8i_rsb_ops, +}; +#endif /* CONFIG_IS_ENABLED(DM_I2C) */ diff --git a/drivers/misc/imx8/scu.c b/drivers/misc/imx8/scu.c index 035a600f71c..4ab5cb4bf13 100644 --- a/drivers/misc/imx8/scu.c +++ b/drivers/misc/imx8/scu.c @@ -219,7 +219,7 @@ static int imx8_scu_bind(struct udevice *dev) debug("%s(dev=%p)\n", __func__, dev); ofnode_for_each_subnode(node, dev_ofnode(dev)) { - ret = lists_bind_fdt(dev, node, &child, true); + ret = lists_bind_fdt(dev, node, &child, NULL, true); if (ret) return ret; debug("bind child dev %s\n", child->name); diff --git a/drivers/mmc/rockchip_sdhci.c b/drivers/mmc/rockchip_sdhci.c index 1ac00587d44..278473899c7 100644 --- a/drivers/mmc/rockchip_sdhci.c +++ b/drivers/mmc/rockchip_sdhci.c @@ -143,6 +143,9 @@ static void rk3399_emmc_phy_power_on(struct rockchip_emmc_phy *phy, u32 clock) writel(RK_CLRSETBITS(3 << 12, freqsel << 12), &phy->emmcphy_con[0]); writel(RK_CLRSETBITS(1 << 1, 1 << 1), &phy->emmcphy_con[6]); + /* REN Enable on STRB Line for HS400 */ + writel(RK_CLRSETBITS(0, 1 << 9), &phy->emmcphy_con[2]); + read_poll_timeout(readl, &phy->emmcphy_status, dllrdy, PHYCTRL_DLL_LOCK_WO_TMOUT(dllrdy), 1, 5000); } diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index aaab0cf8668..c170c16d5ab 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -15,12 +15,11 @@ #include <mmc.h> #include <clk.h> #include <reset.h> +#include <asm/gpio.h> #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/cpu.h> -#include <asm/arch/gpio.h> #include <asm/arch/mmc.h> -#include <asm-generic/gpio.h> #include <linux/delay.h> #ifndef CCM_MMC_CTRL_MODE_SEL_NEW diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 83c055a26ef..a9c8c48ae6f 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -109,6 +109,13 @@ config HBMC_AM654 This is the driver for HyperBus controller on TI's AM65x and other SoCs +config STM32_FLASH + bool "STM32 MCU Flash driver" + depends on ARCH_STM32 + help + This is the driver of embedded flash for some STMicroelectronics + STM32 MCU. + source "drivers/mtd/nand/Kconfig" config SYS_NAND_MAX_CHIPS diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig index d4da639dd13..cb0c0a15818 100644 --- a/drivers/mtd/nand/raw/Kconfig +++ b/drivers/mtd/nand/raw/Kconfig @@ -398,6 +398,12 @@ config NAND_MXS_USE_MINIMUM_ECC endif +config NAND_MXIC + bool "Macronix raw NAND controller" + select SYS_NAND_SELF_INIT + help + This selects the Macronix raw NAND controller driver. + config NAND_ZYNQ bool "Support for Zynq Nand controller" select SYS_NAND_SELF_INIT diff --git a/drivers/mtd/nand/raw/Makefile b/drivers/mtd/nand/raw/Makefile index a5ed2c536f5..6ec3581d20e 100644 --- a/drivers/mtd/nand/raw/Makefile +++ b/drivers/mtd/nand/raw/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o obj-$(CONFIG_NAND_OMAP_ELM) += omap_elm.o obj-$(CONFIG_NAND_PLAT) += nand_plat.o obj-$(CONFIG_NAND_SUNXI) += sunxi_nand.o +obj-$(CONFIG_NAND_MXIC) += mxic_nand.o obj-$(CONFIG_NAND_ZYNQ) += zynq_nand.o obj-$(CONFIG_NAND_STM32_FMC2) += stm32_fmc2_nand.o obj-$(CONFIG_CORTINA_NAND) += cortina_nand.o diff --git a/drivers/mtd/nand/raw/mxic_nand.c b/drivers/mtd/nand/raw/mxic_nand.c new file mode 100644 index 00000000000..e54df4615e9 --- /dev/null +++ b/drivers/mtd/nand/raw/mxic_nand.c @@ -0,0 +1,603 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Macronix International Co., Ltd. + * + * Author: + * Zhengxun Li <zhengxunli@mxic.com.tw> + */ + +#include <common.h> +#include <clk.h> +#include <dm.h> +#include <malloc.h> +#include <nand.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <dm/device_compat.h> +#include <linux/bug.h> +#include <linux/errno.h> +#include <linux/iopoll.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/rawnand.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/delay.h> + +#define HC_CFG 0x0 +#define HC_CFG_IF_CFG(x) ((x) << 27) +#define HC_CFG_DUAL_SLAVE BIT(31) +#define HC_CFG_INDIVIDUAL BIT(30) +#define HC_CFG_NIO(x) (((x) / 4) << 27) +#define HC_CFG_TYPE(s, t) ((t) << (23 + ((s) * 2))) +#define HC_CFG_TYPE_SPI_NOR 0 +#define HC_CFG_TYPE_SPI_NAND 1 +#define HC_CFG_TYPE_SPI_RAM 2 +#define HC_CFG_TYPE_RAW_NAND 3 +#define HC_CFG_SLV_ACT(x) ((x) << 21) +#define HC_CFG_CLK_PH_EN BIT(20) +#define HC_CFG_CLK_POL_INV BIT(19) +#define HC_CFG_BIG_ENDIAN BIT(18) +#define HC_CFG_DATA_PASS BIT(17) +#define HC_CFG_IDLE_SIO_LVL(x) ((x) << 16) +#define HC_CFG_MAN_START_EN BIT(3) +#define HC_CFG_MAN_START BIT(2) +#define HC_CFG_MAN_CS_EN BIT(1) +#define HC_CFG_MAN_CS_ASSERT BIT(0) + +#define INT_STS 0x4 +#define INT_STS_EN 0x8 +#define INT_SIG_EN 0xc +#define INT_STS_ALL GENMASK(31, 0) +#define INT_RDY_PIN BIT(26) +#define INT_RDY_SR BIT(25) +#define INT_LNR_SUSP BIT(24) +#define INT_ECC_ERR BIT(17) +#define INT_CRC_ERR BIT(16) +#define INT_LWR_DIS BIT(12) +#define INT_LRD_DIS BIT(11) +#define INT_SDMA_INT BIT(10) +#define INT_DMA_FINISH BIT(9) +#define INT_RX_NOT_FULL BIT(3) +#define INT_RX_NOT_EMPTY BIT(2) +#define INT_TX_NOT_FULL BIT(1) +#define INT_TX_EMPTY BIT(0) + +#define HC_EN 0x10 +#define HC_EN_BIT BIT(0) + +#define TXD(x) (0x14 + ((x) * 4)) +#define RXD 0x24 + +#define SS_CTRL(s) (0x30 + ((s) * 4)) +#define LRD_CFG 0x44 +#define LWR_CFG 0x80 +#define RWW_CFG 0x70 +#define OP_READ BIT(23) +#define OP_DUMMY_CYC(x) ((x) << 17) +#define OP_ADDR_BYTES(x) ((x) << 14) +#define OP_CMD_BYTES(x) (((x) - 1) << 13) +#define OP_OCTA_CRC_EN BIT(12) +#define OP_DQS_EN BIT(11) +#define OP_ENHC_EN BIT(10) +#define OP_PREAMBLE_EN BIT(9) +#define OP_DATA_DDR BIT(8) +#define OP_DATA_BUSW(x) ((x) << 6) +#define OP_ADDR_DDR BIT(5) +#define OP_ADDR_BUSW(x) ((x) << 3) +#define OP_CMD_DDR BIT(2) +#define OP_CMD_BUSW(x) (x) +#define OP_BUSW_1 0 +#define OP_BUSW_2 1 +#define OP_BUSW_4 2 +#define OP_BUSW_8 3 + +#define OCTA_CRC 0x38 +#define OCTA_CRC_IN_EN(s) BIT(3 + ((s) * 16)) +#define OCTA_CRC_CHUNK(s, x) ((fls((x) / 32)) << (1 + ((s) * 16))) +#define OCTA_CRC_OUT_EN(s) BIT(0 + ((s) * 16)) + +#define ONFI_DIN_CNT(s) (0x3c + (s)) + +#define LRD_CTRL 0x48 +#define RWW_CTRL 0x74 +#define LWR_CTRL 0x84 +#define LMODE_EN BIT(31) +#define LMODE_SLV_ACT(x) ((x) << 21) +#define LMODE_CMD1(x) ((x) << 8) +#define LMODE_CMD0(x) (x) + +#define LRD_ADDR 0x4c +#define LWR_ADDR 0x88 +#define LRD_RANGE 0x50 +#define LWR_RANGE 0x8c + +#define AXI_SLV_ADDR 0x54 + +#define DMAC_RD_CFG 0x58 +#define DMAC_WR_CFG 0x94 +#define DMAC_CFG_PERIPH_EN BIT(31) +#define DMAC_CFG_ALLFLUSH_EN BIT(30) +#define DMAC_CFG_LASTFLUSH_EN BIT(29) +#define DMAC_CFG_QE(x) (((x) + 1) << 16) +#define DMAC_CFG_BURST_LEN(x) (((x) + 1) << 12) +#define DMAC_CFG_BURST_SZ(x) ((x) << 8) +#define DMAC_CFG_DIR_READ BIT(1) +#define DMAC_CFG_START BIT(0) + +#define DMAC_RD_CNT 0x5c +#define DMAC_WR_CNT 0x98 + +#define SDMA_ADDR 0x60 + +#define DMAM_CFG 0x64 +#define DMAM_CFG_START BIT(31) +#define DMAM_CFG_CONT BIT(30) +#define DMAM_CFG_SDMA_GAP(x) (fls((x) / 8192) << 2) +#define DMAM_CFG_DIR_READ BIT(1) +#define DMAM_CFG_EN BIT(0) + +#define DMAM_CNT 0x68 + +#define LNR_TIMER_TH 0x6c + +#define RDM_CFG0 0x78 +#define RDM_CFG0_POLY(x) (x) + +#define RDM_CFG1 0x7c +#define RDM_CFG1_RDM_EN BIT(31) +#define RDM_CFG1_SEED(x) (x) + +#define LWR_SUSP_CTRL 0x90 +#define LWR_SUSP_CTRL_EN BIT(31) + +#define DMAS_CTRL 0x9c +#define DMAS_CTRL_EN BIT(31) +#define DMAS_CTRL_DIR_READ BIT(30) + +#define DATA_STROB 0xa0 +#define DATA_STROB_EDO_EN BIT(2) +#define DATA_STROB_INV_POL BIT(1) +#define DATA_STROB_DELAY_2CYC BIT(0) + +#define IDLY_CODE(x) (0xa4 + ((x) * 4)) +#define IDLY_CODE_VAL(x, v) ((v) << (((x) % 4) * 8)) + +#define GPIO 0xc4 +#define GPIO_PT(x) BIT(3 + ((x) * 16)) +#define GPIO_RESET(x) BIT(2 + ((x) * 16)) +#define GPIO_HOLDB(x) BIT(1 + ((x) * 16)) +#define GPIO_WPB(x) BIT((x) * 16) + +#define HC_VER 0xd0 + +#define HW_TEST(x) (0xe0 + ((x) * 4)) + +#define MXIC_NFC_MAX_CLK_HZ 50000000 +#define IRQ_TIMEOUT 1000 + +struct mxic_nand_ctrl { + struct clk *send_clk; + struct clk *send_dly_clk; + void __iomem *regs; + struct nand_chip nand_chip; +}; + +/* + * struct mxic_nfc_command_format - Defines NAND flash command format + * @start_cmd: First cycle command (Start command) + * @end_cmd: Second cycle command (Last command) + * @addr_len: Number of address cycles required to send the address + * @read: Direction of command + */ + +struct mxic_nfc_command_format { + int start_cmd; + int end_cmd; + u8 addr_len; + bool read; +}; + +/* The NAND flash operations command format */ +static const struct mxic_nfc_command_format mxic_nand_commands[] = { + {NAND_CMD_READ0, NAND_CMD_READSTART, 5, 1 }, + {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, 1 }, + {NAND_CMD_READID, NAND_CMD_NONE, 1, 1 }, + {NAND_CMD_STATUS, NAND_CMD_NONE, 0, 1 }, + {NAND_CMD_SEQIN, NAND_CMD_NONE, 5, 0 }, + {NAND_CMD_PAGEPROG, NAND_CMD_NONE, 0, 0 }, + {NAND_CMD_CACHEDPROG, NAND_CMD_NONE, 0, 0 }, + {NAND_CMD_RNDIN, NAND_CMD_NONE, 2, 0 }, + {NAND_CMD_ERASE1, NAND_CMD_NONE, 3, 0 }, + {NAND_CMD_ERASE2, NAND_CMD_NONE, 0, 0 }, + {NAND_CMD_RESET, NAND_CMD_NONE, 0, 0 }, + {NAND_CMD_PARAM, NAND_CMD_NONE, 1, 1 }, + {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, 1 }, + {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, 1, 0 }, + {NAND_CMD_NONE, NAND_CMD_NONE, 0, 0 }, +}; + +static int mxic_nfc_clk_enable(struct mxic_nand_ctrl *nfc) +{ + int ret; + + ret = clk_prepare_enable(nfc->send_clk); + if (ret) + return ret; + + ret = clk_prepare_enable(nfc->send_dly_clk); + if (ret) + goto err_send_dly_clk; + + return ret; + +err_send_dly_clk: + clk_disable_unprepare(nfc->send_clk); + + return ret; +} + +static void mxic_nfc_clk_disable(struct mxic_nand_ctrl *nfc) +{ + clk_disable_unprepare(nfc->send_clk); + clk_disable_unprepare(nfc->send_dly_clk); +} + +static void mxic_nfc_set_input_delay(struct mxic_nand_ctrl *nfc, u8 idly_code) +{ + writel(IDLY_CODE_VAL(0, idly_code) | + IDLY_CODE_VAL(1, idly_code) | + IDLY_CODE_VAL(2, idly_code) | + IDLY_CODE_VAL(3, idly_code), + nfc->regs + IDLY_CODE(0)); + writel(IDLY_CODE_VAL(4, idly_code) | + IDLY_CODE_VAL(5, idly_code) | + IDLY_CODE_VAL(6, idly_code) | + IDLY_CODE_VAL(7, idly_code), + nfc->regs + IDLY_CODE(1)); +} + +static int mxic_nfc_clk_setup(struct mxic_nand_ctrl *nfc, unsigned long freq) +{ + int ret; + + ret = clk_set_rate(nfc->send_clk, freq); + if (ret) + return ret; + + ret = clk_set_rate(nfc->send_dly_clk, freq); + if (ret) + return ret; + + /* + * A constant delay range from 0x0 ~ 0x1F for input delay, + * the unit is 78 ps, the max input delay is 2.418 ns. + */ + mxic_nfc_set_input_delay(nfc, 0xf); + + return 0; +} + +static int mxic_nfc_set_freq(struct mxic_nand_ctrl *nfc, unsigned long freq) +{ + int ret; + + if (freq > MXIC_NFC_MAX_CLK_HZ) + freq = MXIC_NFC_MAX_CLK_HZ; + + mxic_nfc_clk_disable(nfc); + ret = mxic_nfc_clk_setup(nfc, freq); + if (ret) + return ret; + + ret = mxic_nfc_clk_enable(nfc); + if (ret) + return ret; + + return 0; +} + +static void mxic_nfc_hw_init(struct mxic_nand_ctrl *nfc) +{ + writel(HC_CFG_NIO(8) | HC_CFG_TYPE(1, HC_CFG_TYPE_RAW_NAND) | + HC_CFG_SLV_ACT(0) | HC_CFG_MAN_CS_EN | + HC_CFG_IDLE_SIO_LVL(1), nfc->regs + HC_CFG); + writel(INT_STS_ALL, nfc->regs + INT_STS_EN); + writel(INT_RDY_PIN, nfc->regs + INT_SIG_EN); + writel(0x0, nfc->regs + ONFI_DIN_CNT(0)); + writel(0, nfc->regs + LRD_CFG); + writel(0, nfc->regs + LRD_CTRL); + writel(0x0, nfc->regs + HC_EN); +} + +static void mxic_nfc_cs_enable(struct mxic_nand_ctrl *nfc) +{ + writel(readl(nfc->regs + HC_CFG) | HC_CFG_MAN_CS_EN, + nfc->regs + HC_CFG); + writel(HC_CFG_MAN_CS_ASSERT | readl(nfc->regs + HC_CFG), + nfc->regs + HC_CFG); +} + +static void mxic_nfc_cs_disable(struct mxic_nand_ctrl *nfc) +{ + writel(~HC_CFG_MAN_CS_ASSERT & readl(nfc->regs + HC_CFG), + nfc->regs + HC_CFG); +} + +static int mxic_nfc_data_xfer(struct mxic_nand_ctrl *nfc, const void *txbuf, + void *rxbuf, unsigned int len) +{ + unsigned int pos = 0; + + while (pos < len) { + unsigned int nbytes = len - pos; + u32 data = 0xffffffff; + u32 sts; + int ret; + + if (nbytes > 4) + nbytes = 4; + + if (txbuf) + memcpy(&data, txbuf + pos, nbytes); + + ret = readl_poll_timeout(nfc->regs + INT_STS, sts, + sts & INT_TX_EMPTY, 1000000); + if (ret) + return ret; + + writel(data, nfc->regs + TXD(nbytes % 4)); + + ret = readl_poll_timeout(nfc->regs + INT_STS, sts, + sts & INT_TX_EMPTY, 1000000); + if (ret) + return ret; + + ret = readl_poll_timeout(nfc->regs + INT_STS, sts, + sts & INT_RX_NOT_EMPTY, 1000000); + if (ret) + return ret; + + data = readl(nfc->regs + RXD); + if (rxbuf) { + data >>= (8 * (4 - nbytes)); + memcpy(rxbuf + pos, &data, nbytes); + } + + WARN_ON(readl(nfc->regs + INT_STS) & INT_RX_NOT_EMPTY); + + pos += nbytes; + } + + return 0; +} + +static uint8_t mxic_nfc_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); + u8 data; + + writel(0x0, nfc->regs + ONFI_DIN_CNT(0)); + writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | + OP_READ, nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, NULL, &data, 1); + + return data; +} + +static void mxic_nfc_read_buf(struct mtd_info *mtd, uint8_t *rxbuf, int rlen) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); + + writel(0x0, nfc->regs + ONFI_DIN_CNT(0)); + writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | + OP_READ, nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, NULL, rxbuf, rlen); +} + +static void mxic_nfc_write_buf(struct mtd_info *mtd, const uint8_t *txbuf, + int wlen) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); + + writel(wlen, nfc->regs + ONFI_DIN_CNT(0)); + writel(OP_DATA_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F), + nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, txbuf, NULL, wlen); +} + +static void mxic_nfc_cmd_function(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); + const struct mxic_nfc_command_format *cmd = NULL; + u32 sts; + u8 index, addr[5]; + + /* Emulate NAND_CMD_READOOB */ + if (command == NAND_CMD_READOOB) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Get the command format */ + for (index = 0; index < ARRAY_SIZE(mxic_nand_commands); index++) + if (command == mxic_nand_commands[index].start_cmd) + break; + + cmd = &mxic_nand_commands[index]; + + if (!(command == NAND_CMD_PAGEPROG || + command == NAND_CMD_CACHEDPROG || + command == NAND_CMD_ERASE2)) + mxic_nfc_cs_disable(nfc); + + mxic_nfc_cs_enable(nfc); + + if (column != -1) { + addr[0] = column; + addr[1] = column >> 8; + + if (page_addr != -1) { + addr[2] = page_addr; + addr[3] = page_addr >> 8; + addr[4] = page_addr >> 16; + } + } else if (page_addr != -1) { + addr[0] = page_addr; + addr[1] = page_addr >> 8; + addr[2] = page_addr >> 16; + } + + writel(0, nfc->regs + HC_EN); + writel(HC_EN_BIT, nfc->regs + HC_EN); + writel(OP_CMD_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | OP_CMD_BYTES(0), + nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, &cmd->start_cmd, NULL, 1); + + if (cmd->addr_len) { + writel(OP_ADDR_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | + OP_ADDR_BYTES(cmd->addr_len), nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, &addr, NULL, cmd->addr_len); + } + + if (cmd->end_cmd != NAND_CMD_NONE) { + writel(0, nfc->regs + HC_EN); + writel(HC_EN_BIT, nfc->regs + HC_EN); + writel(OP_CMD_BUSW(OP_BUSW_8) | OP_DUMMY_CYC(0x3F) | + OP_CMD_BYTES(0), nfc->regs + SS_CTRL(0)); + + mxic_nfc_data_xfer(nfc, &cmd->end_cmd, NULL, 1); + } + + readl_poll_timeout(nfc->regs + INT_STS, sts, sts & INT_RDY_PIN, + 1000000); + + if (command == NAND_CMD_PAGEPROG || + command == NAND_CMD_CACHEDPROG || + command == NAND_CMD_ERASE2 || + command == NAND_CMD_RESET) { + mxic_nfc_cs_disable(nfc); + } +} + +static int mxic_nfc_setup_data_interface(struct mtd_info *mtd, int chipnr, + const struct nand_data_interface *conf) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct mxic_nand_ctrl *nfc = nand_get_controller_data(chip); + const struct nand_sdr_timings *sdr; + unsigned long freq; + int ret; + + sdr = nand_get_sdr_timings(conf); + if (IS_ERR(sdr)) + return PTR_ERR(sdr); + + if (chipnr == NAND_DATA_IFACE_CHECK_ONLY) + return 0; + + freq = 1000000000 / (sdr->tRC_min / 1000); + + ret = mxic_nfc_set_freq(nfc, freq); + if (ret) + WARN_ON("Set freq failed\n"); + + if (sdr->tRC_min < 30000) + writel(DATA_STROB_EDO_EN, nfc->regs + DATA_STROB); + + return 0; +} + +/* Dummy implementation: we don't support multiple chips */ +static void mxic_nfc_select_chip(struct mtd_info *mtd, int chipnr) +{ + switch (chipnr) { + case -1: + case 0: + break; + + default: + BUG(); + } +} + +static int mxic_nfc_probe(struct udevice *dev) +{ + struct mxic_nand_ctrl *nfc = dev_get_priv(dev); + struct nand_chip *nand_chip = &nfc->nand_chip; + struct mtd_info *mtd; + ofnode child; + int err; + + nfc->regs = (void *)dev_read_addr(dev); + + nfc->send_clk = devm_clk_get(dev, "send"); + if (IS_ERR(nfc->send_clk)) + return PTR_ERR(nfc->send_clk); + + nfc->send_dly_clk = devm_clk_get(dev, "send_dly"); + if (IS_ERR(nfc->send_dly_clk)) + return PTR_ERR(nfc->send_dly_clk); + + mtd = nand_to_mtd(nand_chip); + + ofnode_for_each_subnode(child, dev_ofnode(dev)) + nand_set_flash_node(nand_chip, child); + + nand_set_controller_data(nand_chip, nfc); + + nand_chip->select_chip = mxic_nfc_select_chip; + nand_chip->setup_data_interface = mxic_nfc_setup_data_interface; + nand_chip->cmdfunc = mxic_nfc_cmd_function; + nand_chip->read_byte = mxic_nfc_read_byte; + nand_chip->read_buf = mxic_nfc_read_buf; + nand_chip->write_buf = mxic_nfc_write_buf; + + mxic_nfc_hw_init(nfc); + + err = nand_scan(mtd, 1); + if (err) + return err; + + err = nand_register(0, mtd); + if (err) { + dev_err(dev, "Failed to register MTD: %d\n", err); + return err; + } + + return 0; +} + +static const struct udevice_id mxic_nfc_of_ids[] = { + { .compatible = "mxic,multi-itfc-v009-nand-controller" }, + { /* Sentinel */ } +}; + +U_BOOT_DRIVER(mxic_nfc) = { + .name = "mxic_nfc", + .id = UCLASS_MTD, + .of_match = mxic_nfc_of_ids, + .probe = mxic_nfc_probe, + .priv_auto = sizeof(struct mxic_nand_ctrl), +}; + +void board_nand_init(void) +{ + struct udevice *dev; + int ret; + + ret = uclass_get_device_by_driver(UCLASS_MTD, + DM_DRIVER_GET(mxic_nfc), &dev); + if (ret && ret != -ENODEV) + pr_err("Failed to initialize %s. (error %d)\n", dev->name, + ret); +} diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 8151104acfc..8c6461e717b 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -574,14 +574,9 @@ static int macb_phy_find(struct macb_device *macb, const char *name) #ifdef CONFIG_DM_ETH static int macb_sifive_clk_init(struct udevice *dev, ulong rate) { - fdt_addr_t addr; void *gemgxl_regs; - addr = dev_read_addr_index(dev, 1); - if (addr == FDT_ADDR_T_NONE) - return -ENODEV; - - gemgxl_regs = (void __iomem *)addr; + gemgxl_regs = dev_read_addr_index_ptr(dev, 1); if (!gemgxl_regs) return -ENODEV; @@ -1383,7 +1378,7 @@ static int macb_eth_probe(struct udevice *dev) macb->phy_addr = ofnode_read_u32_default(phandle_args.node, "reg", -1); - macb->regs = (void *)pdata->iobase; + macb->regs = (void *)(uintptr_t)pdata->iobase; macb->is_big_endian = (cpu_to_be32(0x12345678) == 0x12345678); @@ -1444,7 +1439,7 @@ static int macb_eth_of_to_plat(struct udevice *dev) { struct eth_pdata *pdata = dev_get_plat(dev); - pdata->iobase = (phys_addr_t)dev_remap_addr(dev); + pdata->iobase = (uintptr_t)dev_remap_addr(dev); if (!pdata->iobase) return -EINVAL; diff --git a/drivers/net/sun8i_emac.c b/drivers/net/sun8i_emac.c index a6eb82bd166..2e24d122141 100644 --- a/drivers/net/sun8i_emac.c +++ b/drivers/net/sun8i_emac.c @@ -14,9 +14,9 @@ #include <log.h> #include <asm/cache.h> #include <asm/global_data.h> +#include <asm/gpio.h> #include <asm/io.h> #include <asm/arch/clock.h> -#include <asm/arch/gpio.h> #include <common.h> #include <clk.h> #include <dm.h> @@ -31,9 +31,6 @@ #include <reset.h> #include <dt-bindings/pinctrl/sun4i-a10.h> #include <wait_bit.h> -#if CONFIG_IS_ENABLED(DM_GPIO) -#include <asm-generic/gpio.h> -#endif #define MDIO_CMD_MII_BUSY BIT(0) #define MDIO_CMD_MII_WRITE BIT(1) diff --git a/drivers/nvme/nvme.c b/drivers/nvme/nvme.c index f6465ea7f48..3c529a2fce2 100644 --- a/drivers/nvme/nvme.c +++ b/drivers/nvme/nvme.c @@ -743,6 +743,7 @@ static ulong nvme_blk_rw(struct udevice *udev, lbaint_t blknr, u64 prp2; u64 total_len = blkcnt << desc->log2blksz; u64 temp_len = total_len; + uintptr_t temp_buffer = (uintptr_t)buffer; u64 slba = blknr; u16 lbas = 1 << (dev->max_transfer_shift - ns->lba_shift); @@ -770,19 +771,19 @@ static ulong nvme_blk_rw(struct udevice *udev, lbaint_t blknr, } if (nvme_setup_prps(dev, &prp2, - lbas << ns->lba_shift, (ulong)buffer)) + lbas << ns->lba_shift, temp_buffer)) return -EIO; c.rw.slba = cpu_to_le64(slba); slba += lbas; c.rw.length = cpu_to_le16(lbas - 1); - c.rw.prp1 = cpu_to_le64((ulong)buffer); + c.rw.prp1 = cpu_to_le64(temp_buffer); c.rw.prp2 = cpu_to_le64(prp2); status = nvme_submit_sync_cmd(dev->queues[NVME_IO_Q], &c, NULL, IO_TIMEOUT); if (status) break; temp_len -= (u32)lbas << ns->lba_shift; - buffer += lbas << ns->lba_shift; + temp_buffer += lbas << ns->lba_shift; } if (read) diff --git a/drivers/pci/pci-aardvark.c b/drivers/pci/pci-aardvark.c index cf6e30f936f..38eff495ab1 100644 --- a/drivers/pci/pci-aardvark.c +++ b/drivers/pci/pci-aardvark.c @@ -39,6 +39,9 @@ #define PCIE_CORE_CMD_IO_ACCESS_EN BIT(0) #define PCIE_CORE_CMD_MEM_ACCESS_EN BIT(1) #define PCIE_CORE_CMD_MEM_IO_REQ_EN BIT(2) +#define PCIE_CORE_DEV_REV_REG 0x8 +#define PCIE_CORE_EXP_ROM_BAR_REG 0x30 +#define PCIE_CORE_PCIEXP_CAP_OFF 0xc0 #define PCIE_CORE_DEV_CTRL_STATS_REG 0xc8 #define PCIE_CORE_DEV_CTRL_STATS_RELAX_ORDER_DISABLE (0 << 4) #define PCIE_CORE_DEV_CTRL_STATS_SNOOP_DISABLE (0 << 11) @@ -145,6 +148,7 @@ #define LTSSM_SHIFT 24 #define LTSSM_MASK 0x3f #define LTSSM_L0 0x10 +#define LTSSM_DISABLED 0x20 #define VENDOR_ID_REG (LMI_BASE_ADDR + 0x44) /* PCIe core controller registers */ @@ -162,7 +166,7 @@ #define PCIE_CONFIG_WR_TYPE1 0xb /* PCI_BDF shifts 8bit, so we need extra 4bit shift */ -#define PCIE_BDF(dev) (dev << 4) +#define PCIE_BDF(b, d, f) (PCI_BDF(b, d, f) << 4) #define PCIE_CONF_BUS(bus) (((bus) & 0xff) << 20) #define PCIE_CONF_DEV(dev) (((dev) & 0x1f) << 15) #define PCIE_CONF_FUNC(fun) (((fun) & 0x7) << 12) @@ -182,18 +186,24 @@ /** * struct pcie_advk - Advk PCIe controller state * - * @reg_base: The base address of the register space. - * @first_busno: This driver supports multiple PCIe controllers. - * first_busno stores the bus number of the PCIe root-port - * number which may vary depending on the PCIe setup - * (PEX switches etc). - * @device: The pointer to PCI uclass device. + * @base: The base address of the register space. + * @first_busno: Bus number of the PCIe root-port. + * This may vary depending on the PCIe setup. + * @sec_busno: Bus number for the device behind the PCIe root-port. + * @dev: The pointer to PCI uclass device. + * @reset_gpio: GPIO descriptor for PERST. + * @cfgcache: Buffer for emulation of PCIe Root Port's PCI Bridge registers + * that are not available on Aardvark. + * @cfgcrssve: For CRSSVE emulation. */ struct pcie_advk { - void *base; - int first_busno; - struct udevice *dev; - struct gpio_desc reset_gpio; + void *base; + int first_busno; + int sec_busno; + struct udevice *dev; + struct gpio_desc reset_gpio; + u32 cfgcache[0x34 - 0x10]; + bool cfgcrssve; }; static inline void advk_writel(struct pcie_advk *pcie, uint val, uint reg) @@ -209,22 +219,30 @@ static inline uint advk_readl(struct pcie_advk *pcie, uint reg) /** * pcie_advk_addr_valid() - Check for valid bus address * + * @pcie: Pointer to the PCI bus + * @busno: Bus number of PCI device + * @dev: Device number of PCI device + * @func: Function number of PCI device * @bdf: The PCI device to access - * @first_busno: Bus number of the PCIe controller root complex * - * Return: 1 on valid, 0 on invalid + * Return: true on valid, false on invalid */ -static int pcie_advk_addr_valid(pci_dev_t bdf, int first_busno) +static bool pcie_advk_addr_valid(struct pcie_advk *pcie, + int busno, u8 dev, u8 func) { + /* On the primary (local) bus there is only one PCI Bridge */ + if (busno == pcie->first_busno && (dev != 0 || func != 0)) + return false; + /* - * In PCIE-E only a single device (0) can exist - * on the local bus. Beyound the local bus, there might be - * a Switch and everything is possible. + * In PCI-E only a single device (0) can exist on the secondary bus. + * Beyond the secondary bus, there might be a Switch and anything is + * possible. */ - if ((PCI_BUS(bdf) == first_busno) && (PCI_DEV(bdf) > 0)) - return 0; + if (busno == pcie->sec_busno && dev != 0) + return false; - return 1; + return true; } /** @@ -354,32 +372,80 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, enum pci_size_t size) { struct pcie_advk *pcie = dev_get_priv(bus); + int busno = PCI_BUS(bdf) - dev_seq(bus); int retry_count; bool allow_crs; + ulong data; uint reg; int ret; dev_dbg(pcie->dev, "PCIE CFG read: (b,d,f)=(%2d,%2d,%2d) ", PCI_BUS(bdf), PCI_DEV(bdf), PCI_FUNC(bdf)); - if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) { + if (!pcie_advk_addr_valid(pcie, busno, PCI_DEV(bdf), PCI_FUNC(bdf))) { dev_dbg(pcie->dev, "- out of range\n"); *valuep = pci_get_ff(size); return 0; } /* + * The configuration space of the PCI Bridge on primary (local) bus is + * not accessible via PIO transfers like all other PCIe devices. PCI + * Bridge config registers are available directly in Aardvark memory + * space starting at offset zero. Moreover PCI Bridge registers in the + * range 0x10 - 0x34 are not available and register 0x38 (Expansion ROM + * Base Address) is at offset 0x30. + * We therefore read configuration space content of the primary PCI + * Bridge from our virtual cache. + */ + if (busno == pcie->first_busno) { + if (offset >= 0x10 && offset < 0x34) + data = pcie->cfgcache[(offset - 0x10) / 4]; + else if ((offset & ~3) == PCI_ROM_ADDRESS1) + data = advk_readl(pcie, PCIE_CORE_EXP_ROM_BAR_REG); + else + data = advk_readl(pcie, offset & ~3); + + if ((offset & ~3) == (PCI_HEADER_TYPE & ~3)) { + /* + * Change Header Type of PCI Bridge device to Type 1 + * (0x01, used by PCI Bridges) because hardwired value + * is Type 0 (0x00, used by Endpoint devices). + */ + data &= ~0x007f0000; + data |= PCI_HEADER_TYPE_BRIDGE << 16; + } + + if ((offset & ~3) == PCIE_CORE_PCIEXP_CAP_OFF + PCI_EXP_RTCTL) { + /* CRSSVE bit is stored only in cache */ + if (pcie->cfgcrssve) + data |= PCI_EXP_RTCTL_CRSSVE; + } + + if ((offset & ~3) == PCIE_CORE_PCIEXP_CAP_OFF + + (PCI_EXP_RTCAP & ~3)) { + /* CRS is emulated below, so set CRSVIS capability */ + data |= PCI_EXP_RTCAP_CRSVIS << 16; + } + + *valuep = pci_conv_32_to_size(data, offset, size); + + return 0; + } + + /* * Returning fabricated CRS value (0xFFFF0001) by PCIe Root Complex to * OS is allowed only for 4-byte PCI_VENDOR_ID config read request and * only when CRSSVE bit in Root Port PCIe device is enabled. In all * other error PCIe Root Complex must return all-ones. - * Aardvark HW does not have Root Port PCIe device and U-Boot does not - * implement emulation of this device. + * * U-Boot currently does not support handling of CRS return value for * PCI_VENDOR_ID config read request and also does not set CRSSVE bit. - * Therefore disable returning CRS response for now. + * So it means that pcie->cfgcrssve is false. But the code is prepared + * for returning CRS, so that if U-Boot does support CRS in the future, + * it will work for Aardvark. */ - allow_crs = false; + allow_crs = pcie->cfgcrssve; if (advk_readl(pcie, PIO_START)) { dev_err(pcie->dev, @@ -395,14 +461,14 @@ static int pcie_advk_read_config(const struct udevice *bus, pci_dev_t bdf, /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); reg &= ~PIO_CTRL_TYPE_MASK; - if (PCI_BUS(bdf) == pcie->first_busno) + if (busno == pcie->sec_busno) reg |= PCIE_CONFIG_RD_TYPE0; else reg |= PCIE_CONFIG_RD_TYPE1; advk_writel(pcie, reg, PIO_CTRL); /* Program the address registers */ - reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset); + reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset); advk_writel(pcie, reg, PIO_ADDR_LS); advk_writel(pcie, 0, PIO_ADDR_MS); @@ -490,7 +556,9 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, enum pci_size_t size) { struct pcie_advk *pcie = dev_get_priv(bus); + int busno = PCI_BUS(bdf) - dev_seq(bus); int retry_count; + ulong data; uint reg; int ret; @@ -499,11 +567,44 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, dev_dbg(pcie->dev, "(addr,size,val)=(0x%04x, %d, 0x%08lx)\n", offset, size, value); - if (!pcie_advk_addr_valid(bdf, pcie->first_busno)) { + if (!pcie_advk_addr_valid(pcie, busno, PCI_DEV(bdf), PCI_FUNC(bdf))) { dev_dbg(pcie->dev, "- out of range\n"); return 0; } + /* + * As explained in pcie_advk_read_config(), for the configuration + * space of the primary PCI Bridge, we write the content into virtual + * cache. + */ + if (busno == pcie->first_busno) { + if (offset >= 0x10 && offset < 0x34) { + data = pcie->cfgcache[(offset - 0x10) / 4]; + data = pci_conv_size_to_32(data, value, offset, size); + pcie->cfgcache[(offset - 0x10) / 4] = data; + } else if ((offset & ~3) == PCI_ROM_ADDRESS1) { + data = advk_readl(pcie, PCIE_CORE_EXP_ROM_BAR_REG); + data = pci_conv_size_to_32(data, value, offset, size); + advk_writel(pcie, data, PCIE_CORE_EXP_ROM_BAR_REG); + } else { + data = advk_readl(pcie, offset & ~3); + data = pci_conv_size_to_32(data, value, offset, size); + advk_writel(pcie, data, offset & ~3); + } + + if (offset == PCI_PRIMARY_BUS) + pcie->first_busno = data & 0xff; + + if (offset == PCI_SECONDARY_BUS || + (offset == PCI_PRIMARY_BUS && size != PCI_SIZE_8)) + pcie->sec_busno = (data >> 8) & 0xff; + + if ((offset & ~3) == PCIE_CORE_PCIEXP_CAP_OFF + PCI_EXP_RTCTL) + pcie->cfgcrssve = data & PCI_EXP_RTCTL_CRSSVE; + + return 0; + } + if (advk_readl(pcie, PIO_START)) { dev_err(pcie->dev, "Previous PIO read/write transfer is still running\n"); @@ -513,14 +614,14 @@ static int pcie_advk_write_config(struct udevice *bus, pci_dev_t bdf, /* Program the control register */ reg = advk_readl(pcie, PIO_CTRL); reg &= ~PIO_CTRL_TYPE_MASK; - if (PCI_BUS(bdf) == pcie->first_busno) + if (busno == pcie->sec_busno) reg |= PCIE_CONFIG_WR_TYPE0; else reg |= PCIE_CONFIG_WR_TYPE1; advk_writel(pcie, reg, PIO_CTRL); /* Program the address registers */ - reg = PCIE_BDF(bdf) | PCIE_CONF_REG(offset); + reg = PCIE_BDF(busno, PCI_DEV(bdf), PCI_FUNC(bdf)) | PCIE_CONF_REG(offset); advk_writel(pcie, reg, PIO_ADDR_LS); advk_writel(pcie, 0, PIO_ADDR_MS); dev_dbg(pcie->dev, "\tPIO req. - addr = 0x%08x\n", reg); @@ -569,7 +670,7 @@ static int pcie_advk_link_up(struct pcie_advk *pcie) val = advk_readl(pcie, CFG_REG); ltssm_state = (val >> LTSSM_SHIFT) & LTSSM_MASK; - return ltssm_state >= LTSSM_L0; + return ltssm_state >= LTSSM_L0 && ltssm_state < LTSSM_DISABLED; } /** @@ -589,14 +690,14 @@ static int pcie_advk_wait_for_link(struct pcie_advk *pcie) /* check if the link is up or not */ for (retries = 0; retries < LINK_MAX_RETRIES; retries++) { if (pcie_advk_link_up(pcie)) { - printf("PCIE-%d: Link up\n", pcie->first_busno); + printf("PCIe: Link up\n"); return 0; } udelay(LINK_WAIT_TIMEOUT); } - printf("PCIE-%d: Link down\n", pcie->first_busno); + printf("PCIe: Link down\n"); return -ETIMEDOUT; } @@ -715,6 +816,25 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie) */ advk_writel(pcie, 0x11ab11ab, VENDOR_ID_REG); + /* + * Change Class Code of PCI Bridge device to PCI Bridge (0x600400), + * because default value is Mass Storage Controller (0x010400), causing + * U-Boot to fail to recognize it as P2P Bridge. + * + * Note that this Aardvark PCI Bridge does not have a compliant Type 1 + * Configuration Space and it even cannot be accessed via Aardvark's + * PCI config space access method. Something like config space is + * available in internal Aardvark registers starting at offset 0x0 + * and is reported as Type 0. In range 0x10 - 0x34 it has totally + * different registers. So our driver reports Header Type as Type 1 and + * for the above mentioned range redirects access to the virtual + * cfgcache[] buffer, which avoids changing internal Aardvark registers. + */ + reg = advk_readl(pcie, PCIE_CORE_DEV_REV_REG); + reg &= ~0xffffff00; + reg |= (PCI_CLASS_BRIDGE_PCI << 8) << 8; + advk_writel(pcie, reg, PCIE_CORE_DEV_REV_REG); + /* Set Advanced Error Capabilities and Control PF0 register */ reg = PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX | PCIE_CORE_ERR_CAPCTL_ECRC_CHK_TX_EN | @@ -809,12 +929,6 @@ static int pcie_advk_setup_hw(struct pcie_advk *pcie) if (pcie_advk_wait_for_link(pcie)) return -ENXIO; - reg = advk_readl(pcie, PCIE_CORE_CMD_STATUS_REG); - reg |= PCIE_CORE_CMD_MEM_ACCESS_EN | - PCIE_CORE_CMD_IO_ACCESS_EN | - PCIE_CORE_CMD_MEM_IO_REQ_EN; - advk_writel(pcie, reg, PCIE_CORE_CMD_STATUS_REG); - return 0; } @@ -856,9 +970,14 @@ static int pcie_advk_probe(struct udevice *dev) dev_warn(dev, "PCIE Reset on GPIO support is missing\n"); } - pcie->first_busno = dev_seq(dev); pcie->dev = pci_get_controller(dev); + /* PCI Bridge support 32-bit I/O and 64-bit prefetch mem addressing */ + pcie->cfgcache[(PCI_IO_BASE - 0x10) / 4] = + PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8); + pcie->cfgcache[(PCI_PREF_MEMORY_BASE - 0x10) / 4] = + PCI_PREF_RANGE_TYPE_64 | (PCI_PREF_RANGE_TYPE_64 << 16); + return pcie_advk_setup_hw(pcie); } diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index 044babee164..5da3515f5f2 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -627,6 +627,7 @@ int pci_generic_mmap_read_config( int dm_pci_hose_probe_bus(struct udevice *bus) { + u8 header_type; int sub_bus; int ret; int ea_pos; @@ -634,6 +635,14 @@ int dm_pci_hose_probe_bus(struct udevice *bus) debug("%s\n", __func__); + dm_pci_read_config8(bus, PCI_HEADER_TYPE, &header_type); + header_type &= 0x7f; + if (header_type != PCI_HEADER_TYPE_BRIDGE) { + debug("%s: Skipping PCI device %d with Non-Bridge Header Type 0x%x\n", + __func__, PCI_DEV(dm_pci_get_bdf(bus)), header_type); + return log_msg_ret("probe", -EINVAL); + } + ea_pos = dm_pci_find_capability(bus, PCI_CAP_ID_EA); if (ea_pos) { dm_pci_read_config8(bus, ea_pos + sizeof(u32) + sizeof(u8), diff --git a/drivers/pci/pci_auto.c b/drivers/pci/pci_auto.c index 08082460eb8..5af4ee6e56d 100644 --- a/drivers/pci/pci_auto.c +++ b/drivers/pci/pci_auto.c @@ -19,7 +19,7 @@ #define CONFIG_SYS_PCI_CACHE_LINE_SIZE 8 #endif -static void dm_pciauto_setup_device(struct udevice *dev, int bars_num, +static void dm_pciauto_setup_device(struct udevice *dev, struct pci_region *mem, struct pci_region *prefetch, struct pci_region *io) @@ -28,6 +28,7 @@ static void dm_pciauto_setup_device(struct udevice *dev, int bars_num, pci_size_t bar_size; u16 cmdstat = 0; int bar, bar_nr = 0; + int bars_num; u8 header_type; int rom_addr; pci_addr_t bar_value; @@ -39,6 +40,26 @@ static void dm_pciauto_setup_device(struct udevice *dev, int bars_num, cmdstat = (cmdstat & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) | PCI_COMMAND_MASTER; + dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type); + header_type &= 0x7f; + + switch (header_type) { + case PCI_HEADER_TYPE_NORMAL: + bars_num = 6; + break; + case PCI_HEADER_TYPE_BRIDGE: + bars_num = 2; + break; + case PCI_HEADER_TYPE_CARDBUS: + /* CardBus header does not have any BAR */ + bars_num = 0; + break; + default: + /* Skip configuring BARs for unknown header types */ + bars_num = 0; + break; + } + for (bar = PCI_BASE_ADDRESS_0; bar < PCI_BASE_ADDRESS_0 + (bars_num * 4); bar += 4) { int ret = 0; @@ -129,9 +150,8 @@ static void dm_pciauto_setup_device(struct udevice *dev, int bars_num, } /* Configure the expansion ROM address */ - dm_pci_read_config8(dev, PCI_HEADER_TYPE, &header_type); - header_type &= 0x7f; - if (header_type != PCI_HEADER_TYPE_CARDBUS) { + if (header_type == PCI_HEADER_TYPE_NORMAL || + header_type == PCI_HEADER_TYPE_BRIDGE) { rom_addr = (header_type == PCI_HEADER_TYPE_NORMAL) ? PCI_ROM_ADDRESS : PCI_ROM_ADDRESS1; dm_pci_write_config32(dev, rom_addr, 0xfffffffe); @@ -342,7 +362,7 @@ int dm_pciauto_config_device(struct udevice *dev) debug("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_DEV(dm_pci_get_bdf(dev))); - dm_pciauto_setup_device(dev, 2, pci_mem, pci_prefetch, pci_io); + dm_pciauto_setup_device(dev, pci_mem, pci_prefetch, pci_io); ret = dm_pci_hose_probe_bus(dev); if (ret < 0) @@ -355,7 +375,7 @@ int dm_pciauto_config_device(struct udevice *dev) * just do a minimal setup of the bridge, * let the OS take care of the rest */ - dm_pciauto_setup_device(dev, 0, pci_mem, pci_prefetch, pci_io); + dm_pciauto_setup_device(dev, pci_mem, pci_prefetch, pci_io); debug("PCI Autoconfig: Found P2CardBus bridge, device %d\n", PCI_DEV(dm_pci_get_bdf(dev))); @@ -387,7 +407,7 @@ int dm_pciauto_config_device(struct udevice *dev) /* fall through */ default: - dm_pciauto_setup_device(dev, 6, pci_mem, pci_prefetch, pci_io); + dm_pciauto_setup_device(dev, pci_mem, pci_prefetch, pci_io); break; } diff --git a/drivers/pci/pci_auto_common.c b/drivers/pci/pci_auto_common.c index c0a53dcc929..2f4aff01049 100644 --- a/drivers/pci/pci_auto_common.c +++ b/drivers/pci/pci_auto_common.c @@ -74,7 +74,7 @@ static void pciauto_show_region(const char *name, struct pci_region *region) { pciauto_region_init(region); debug("PCI Autoconfig: Bus %s region: [%llx-%llx],\n" - "\t\tPhysical Memory [%llx-%llxx]\n", name, + "\t\tPhysical Memory [%llx-%llx]\n", name, (unsigned long long)region->bus_start, (unsigned long long)(region->bus_start + region->size - 1), (unsigned long long)region->phys_start, diff --git a/drivers/pci/pcie_dw_meson.c b/drivers/pci/pcie_dw_meson.c index 0525ecbea64..07da9fa5332 100644 --- a/drivers/pci/pcie_dw_meson.c +++ b/drivers/pci/pcie_dw_meson.c @@ -319,15 +319,9 @@ static int meson_pcie_init_port(struct udevice *dev) pcie_dw_setup_host(&priv->dw); - ret = meson_pcie_link_up(priv, LINK_SPEED_GEN_2); - if (ret < 0) - goto err_link_up; + meson_pcie_link_up(priv, LINK_SPEED_GEN_2); return 0; -err_link_up: - clk_disable(&priv->clk_port); - clk_disable(&priv->clk_general); - clk_disable(&priv->clk_pclk); err_deassert_bulk: reset_assert_bulk(&priv->rsts); err_power_off_phy: diff --git a/drivers/phy/marvell/comphy_a3700.c b/drivers/phy/marvell/comphy_a3700.c index 06822d1d12e..047c8bb0452 100644 --- a/drivers/phy/marvell/comphy_a3700.c +++ b/drivers/phy/marvell/comphy_a3700.c @@ -200,7 +200,7 @@ static int comphy_pcie_power_up(u32 speed, u32 invert) * 6. Enable the output of 100M/125M/500M clock */ reg_set16(phy_addr(PCIE, MISC_REG0), - 0xA00D | rb_clk500m_en | rb_clk100m_125m_en, 0xFFFF); + 0xA00D | rb_clk500m_en | rb_txdclk_2x_sel | rb_clk100m_125m_en, 0xFFFF); /* * 7. Enable TX @@ -230,9 +230,13 @@ static int comphy_pcie_power_up(u32 speed, u32 invert) */ if (invert & COMPHY_POLARITY_TXD_INVERT) reg_set16(phy_addr(PCIE, SYNC_PATTERN), phy_txd_inv, 0); + else + reg_set16(phy_addr(PCIE, SYNC_PATTERN), 0, phy_txd_inv); if (invert & COMPHY_POLARITY_RXD_INVERT) reg_set16(phy_addr(PCIE, SYNC_PATTERN), phy_rxd_inv, 0); + else + reg_set16(phy_addr(PCIE, SYNC_PATTERN), 0, phy_rxd_inv); /* * 11. Release SW reset @@ -467,9 +471,13 @@ static int comphy_usb3_power_up(u32 lane, u32 type, u32 speed, u32 invert) */ if (invert & COMPHY_POLARITY_TXD_INVERT) usb3_reg_set16(SYNC_PATTERN, phy_txd_inv, 0, lane); + else + usb3_reg_set16(SYNC_PATTERN, 0, phy_txd_inv, lane); if (invert & COMPHY_POLARITY_RXD_INVERT) usb3_reg_set16(SYNC_PATTERN, phy_rxd_inv, 0, lane); + else + usb3_reg_set16(SYNC_PATTERN, 0, phy_rxd_inv, lane); /* * 10. Set max speed generation to USB3.0 5Gbps @@ -586,24 +594,30 @@ static int comphy_usb2_power_up(u8 usb32) rb_usb2phy_pllcal_done, /* value */ rb_usb2phy_pllcal_done, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to end USB2 PLL calibration\n"); + goto out; + } /* Assert impedance calibration done */ ret = comphy_poll_reg(USB2_PHY_CAL_CTRL_ADDR(usb32), rb_usb2phy_impcal_done, /* value */ rb_usb2phy_impcal_done, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to end USB2 impedance calibration\n"); + goto out; + } /* Assert squetch calibration done */ ret = comphy_poll_reg(USB2_PHY_RX_CHAN_CTRL1_ADDR(usb32), rb_usb2phy_sqcal_done, /* value */ rb_usb2phy_sqcal_done, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to end USB2 unknown calibration\n"); + goto out; + } /* Assert PLL is ready */ ret = comphy_poll_reg(USB2_PHY_PLL_CTRL0_ADDR(usb32), @@ -611,9 +625,12 @@ static int comphy_usb2_power_up(u8 usb32) rb_usb2phy_pll_ready, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to lock USB2 PLL\n"); + goto out; + } +out: debug_exit(); return ret; @@ -839,9 +856,13 @@ static int comphy_sgmii_power_up(u32 lane, u32 speed, u32 invert) */ if (invert & COMPHY_POLARITY_TXD_INVERT) reg_set16(sgmiiphy_addr(lane, SYNC_PATTERN), phy_txd_inv, 0); + else + reg_set16(sgmiiphy_addr(lane, SYNC_PATTERN), 0, phy_txd_inv); if (invert & COMPHY_POLARITY_RXD_INVERT) reg_set16(sgmiiphy_addr(lane, SYNC_PATTERN), phy_rxd_inv, 0); + else + reg_set16(sgmiiphy_addr(lane, SYNC_PATTERN), 0, phy_rxd_inv); /* * 19. Set PHY input ports PIN_PU_PLL, PIN_PU_TX and PIN_PU_RX to 1 @@ -861,8 +882,10 @@ static int comphy_sgmii_power_up(u32 lane, u32 speed, u32 invert) rb_pll_ready_tx | rb_pll_ready_rx, /* value */ rb_pll_ready_tx | rb_pll_ready_rx, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to lock PLL for SGMII PHY %d\n", lane); + goto out; + } /* * 21. Set COMPHY input port PIN_TX_IDLE=0 @@ -883,14 +906,17 @@ static int comphy_sgmii_power_up(u32 lane, u32 speed, u32 invert) rb_rx_init_done, /* value */ rb_rx_init_done, /* mask */ POLL_32B_REG); /* 32bit */ - if (!ret) + if (!ret) { printf("Failed to init RX of SGMII PHY %d\n", lane); + goto out; + } /* * Restore saved selector. */ reg_set(COMPHY_SEL_ADDR, saved_selector, 0xFFFFFFFF); +out: debug_exit(); return ret; diff --git a/drivers/phy/marvell/comphy_a3700.h b/drivers/phy/marvell/comphy_a3700.h index 8748c6c84ae..23c8ffbff44 100644 --- a/drivers/phy/marvell/comphy_a3700.h +++ b/drivers/phy/marvell/comphy_a3700.h @@ -120,6 +120,7 @@ static inline void __iomem *phy_addr(enum phy_unit unit, u32 addr) #define MISC_REG0 0x4f #define rb_clk100m_125m_en BIT(4) +#define rb_txdclk_2x_sel BIT(6) #define rb_clk500m_en BIT(7) #define rb_ref_clk_sel BIT(10) diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index 02d859a0398..9c1dcfae524 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -339,8 +339,8 @@ static int stm32_usbphyc_probe(struct udevice *dev) { struct stm32_usbphyc *usbphyc = dev_get_priv(dev); struct reset_ctl reset; - ofnode node; - int i, ret; + ofnode node, connector; + int ret; usbphyc->base = dev_read_addr(dev); if (usbphyc->base == FDT_ADDR_T_NONE) @@ -378,14 +378,18 @@ static int stm32_usbphyc_probe(struct udevice *dev) return ret; } - /* - * parse all PHY subnodes in order to populate regulator associated - * to each PHY port - */ - node = dev_read_first_subnode(dev); - for (i = 0; i < MAX_PHYS; i++) { - struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys + i; + /* parse all PHY subnodes to populate regulator associated to each PHY port */ + dev_for_each_subnode(node, dev) { + fdt_addr_t phy_id; + struct stm32_usbphyc_phy *usbphyc_phy; + phy_id = ofnode_read_u32_default(node, "reg", FDT_ADDR_T_NONE); + if (phy_id >= MAX_PHYS) { + dev_err(dev, "invalid reg value %lx for %s\n", + phy_id, ofnode_get_name(node)); + return -ENOENT; + } + usbphyc_phy = usbphyc->phys + phy_id; usbphyc_phy->init = false; usbphyc_phy->powered = false; ret = stm32_usbphyc_get_regulator(node, "phy-supply", @@ -395,12 +399,12 @@ static int stm32_usbphyc_probe(struct udevice *dev) return ret; } - ret = stm32_usbphyc_get_regulator(node, "vbus-supply", - &usbphyc_phy->vbus); - if (ret) - usbphyc_phy->vbus = NULL; - - node = dev_read_next_subnode(node); + usbphyc_phy->vbus = NULL; + connector = ofnode_find_subnode(node, "connector"); + if (ofnode_valid(connector)) { + ret = stm32_usbphyc_get_regulator(connector, "vbus-supply", + &usbphyc_phy->vbus); + } } /* Check if second port has to be used for host controller */ diff --git a/drivers/power/axp809.c b/drivers/power/axp809.c index 6323492b66d..0396502cdb5 100644 --- a/drivers/power/axp809.c +++ b/drivers/power/axp809.c @@ -13,7 +13,6 @@ #include <common.h> #include <command.h> #include <errno.h> -#include <asm/arch/gpio.h> #include <asm/arch/pmic_bus.h> #include <axp_pmic.h> diff --git a/drivers/power/axp818.c b/drivers/power/axp818.c index 0531707c8aa..2dc736467bb 100644 --- a/drivers/power/axp818.c +++ b/drivers/power/axp818.c @@ -13,7 +13,6 @@ #include <common.h> #include <command.h> #include <errno.h> -#include <asm/arch/gpio.h> #include <asm/arch/pmic_bus.h> #include <axp_pmic.h> diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index cf2a9b2c17e..92e2ace279d 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -10,10 +10,12 @@ config DM_PMIC - 'drivers/power/pmic/pmic-uclass.c' - 'include/power/pmic.h' +if DM_PMIC + config SPL_DM_PMIC bool "Enable Driver Model for PMIC drivers (UCLASS_PMIC) in SPL" depends on SPL_DM - default y if DM_PMIC + default y ---help--- This config enables the driver-model PMIC support in SPL. UCLASS_PMIC - designed to provide an I/O interface for PMIC devices. @@ -25,7 +27,6 @@ config SPL_DM_PMIC config PMIC_CHILDREN bool "Allow child devices for PMICs" - depends on DM_PMIC default y ---help--- This allows PMICs to support child devices (such as regulators) in @@ -35,7 +36,7 @@ config PMIC_CHILDREN config SPL_PMIC_CHILDREN bool "Allow child devices for PMICs in SPL" - depends on DM_PMIC + depends on SPL_DM_PMIC default y ---help--- This allows PMICs to support child devices (such as regulators) in @@ -46,7 +47,6 @@ config SPL_PMIC_CHILDREN config PMIC_AB8500 bool "Enable driver for ST-Ericsson AB8500 PMIC via PRCMU" - depends on DM_PMIC select REGMAP select SYSCON help @@ -56,23 +56,36 @@ config PMIC_AB8500 config PMIC_ACT8846 bool "Enable support for the active-semi 8846 PMIC" - depends on DM_PMIC && DM_I2C + depends on DM_I2C ---help--- This PMIC includes 4 DC/DC step-down buck regulators and 8 low-dropout regulators (LDOs). It also provides some GPIO, reset and battery functions. It uses an I2C interface and is designed for use with tablets and smartphones. +config PMIC_AXP + bool "Enable Driver Model for X-Powers AXP PMICs" + depends on DM_I2C + help + This config enables driver-model PMIC uclass features for + X-Powers AXP152, AXP2xx, and AXP8xx PMICs. + +config SPL_PMIC_AXP + bool "Enable Driver Model for X-Powers AXP PMICs in SPL" + depends on SPL_DM_I2C && SPL_DM_PMIC + help + This config enables driver-model PMIC uclass features in the SPL for + X-Powers AXP152, AXP2xx, and AXP8xx PMICs. + config DM_PMIC_DA9063 bool "Enable Driver Model for the Dialog DA9063 PMIC" - depends on DM_PMIC help This config enables implementation of driver-model pmic uclass features for PMIC DA9063. The driver implements read/write operations. config SPL_DM_PMIC_DA9063 bool "Enable Driver Model for the Dialog DA9063 PMIC in SPL" - depends on DM_PMIC && SPL + depends on SPL_DM_PMIC help This config enables implementation of driver-model pmic uclass features for PMIC DA9063. The driver implements read/write operations. @@ -87,14 +100,13 @@ config PMIC_AS3722 config DM_PMIC_BD71837 bool "Enable Driver Model for PMIC BD71837" - depends on DM_PMIC help This config enables implementation of driver-model pmic uclass features for PMIC BD71837. The driver implements read/write operations. config SPL_DM_PMIC_BD71837 bool "Enable Driver Model for PMIC BD71837 in SPL stage" - depends on DM_PMIC + depends on SPL_DM_PMIC help This config enables implementation of driver-model pmic uclass features for PMIC BD71837. The driver implements read/write @@ -102,7 +114,7 @@ config SPL_DM_PMIC_BD71837 config DM_PMIC_FAN53555 bool "Enable support for OnSemi FAN53555" - depends on DM_PMIC && DM_REGULATOR && DM_I2C + depends on DM_REGULATOR && DM_I2C select DM_REGULATOR_FAN53555 help This config enables implementation of driver-model PMIC @@ -116,14 +128,13 @@ config DM_PMIC_FAN53555 config DM_PMIC_MP5416 bool "Enable Driver Model for PMIC MP5416" - depends on DM_PMIC help This config enables implementation of driver-model pmic uclass features for PMIC MP5416. The driver implements read/write operations. config SPL_DM_PMIC_MP5416 bool "Enable Driver Model for PMIC MP5416 in SPL stage" - depends on DM_PMIC + depends on SPL_DM_PMIC help This config enables implementation of driver-model pmic uclass features for PMIC MP5416. The driver implements read/write @@ -131,56 +142,50 @@ config SPL_DM_PMIC_MP5416 config DM_PMIC_PCA9450 bool "Enable Driver Model for PMIC PCA9450" - depends on DM_PMIC help This config enables implementation of driver-model pmic uclass features for PMIC PCA9450. The driver implements read/write operations. config SPL_DM_PMIC_PCA9450 bool "Enable Driver Model for PMIC PCA9450" - depends on DM_PMIC + depends on SPL_DM_PMIC help This config enables implementation of driver-model pmic uclass features for PMIC PCA9450 in SPL. The driver implements read/write operations. config DM_PMIC_PFUZE100 bool "Enable Driver Model for PMIC PFUZE100" - depends on DM_PMIC ---help--- This config enables implementation of driver-model pmic uclass features for PMIC PFUZE100. The driver implements read/write operations. config SPL_DM_PMIC_PFUZE100 bool "Enable Driver Model for PMIC PFUZE100 in SPL" - depends on DM_PMIC + depends on SPL_DM_PMIC ---help--- This config enables implementation of driver-model pmic uclass features for PMIC PFUZE100 in SPL. The driver implements read/write operations. config DM_PMIC_MAX77686 bool "Enable Driver Model for PMIC MAX77686" - depends on DM_PMIC ---help--- This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations. config DM_PMIC_MAX8998 bool "Enable Driver Model for PMIC MAX8998" - depends on DM_PMIC ---help--- This config enables implementation of driver-model pmic uclass features for PMIC MAX8998. The driver implements read/write operations. config DM_PMIC_MC34708 bool "Enable Driver Model for PMIC MC34708" - depends on DM_PMIC help This config enables implementation of driver-model pmic uclass features for PMIC MC34708. The driver implements read/write operations. config PMIC_MAX8997 bool "Enable Driver Model for PMIC MAX8997" - depends on DM_PMIC ---help--- This config enables implementation of driver-model pmic uclass features for PMIC MAX8997. The driver implements read/write operations. @@ -195,7 +200,6 @@ config PMIC_MAX8997 config PMIC_PM8916 bool "Enable Driver Model for Qualcomm PM8916 PMIC" - depends on DM_PMIC ---help--- The PM8916 is a PMIC connected to one (or several) processors with SPMI bus. It has 2 slaves with several peripherals: @@ -211,7 +215,6 @@ config PMIC_PM8916 config PMIC_RK8XX bool "Enable support for Rockchip PMIC RK8XX" - depends on DM_PMIC ---help--- The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs, an RTC and two low Rds (resistance (drain to source)) switches. It is @@ -220,7 +223,7 @@ config PMIC_RK8XX config SPL_PMIC_RK8XX bool "Enable support for Rockchip PMIC RK8XX" - depends on DM_PMIC + depends on SPL_DM_PMIC ---help--- The Rockchip RK808 PMIC provides four buck DC-DC convertors, 8 LDOs, an RTC and two low Rds (resistance (drain to source)) switches. It is @@ -229,7 +232,6 @@ config SPL_PMIC_RK8XX config PMIC_S2MPS11 bool "Enable Driver Model for PMIC Samsung S2MPS11" - depends on DM_PMIC ---help--- The Samsung S2MPS11 PMIC provides: - 38 adjustable LDO regulators @@ -243,7 +245,6 @@ config PMIC_S2MPS11 config DM_PMIC_SANDBOX bool "Enable Driver Model for emulated Sandbox PMIC" - depends on DM_PMIC ---help--- Enable the driver for Sandbox PMIC emulation. The emulated PMIC device depends on two drivers: @@ -268,7 +269,6 @@ config DM_PMIC_SANDBOX config PMIC_S5M8767 bool "Enable Driver Model for the Samsung S5M8767 PMIC" - depends on DM_PMIC ---help--- The S5M8767 PMIC provides a large array of LDOs and BUCKs for use as a SoC power controller. It also provides 32KHz clock outputs. This @@ -277,7 +277,6 @@ config PMIC_S5M8767 config PMIC_RN5T567 bool "Enable driver for Ricoh RN5T567 PMIC" - depends on DM_PMIC ---help--- The RN5T567 is a PMIC with 4 step-down DC/DC converters, 5 LDO regulators Real-Time Clock and 4 GPIOs. This driver provides @@ -285,7 +284,6 @@ config PMIC_RN5T567 config PMIC_TPS65090 bool "Enable driver for Texas Instruments TPS65090 PMIC" - depends on DM_PMIC ---help--- The TPS65090 is a PMIC containing several LDOs, DC to DC convertors, FETs and a battery charger. This driver provides register access @@ -294,35 +292,24 @@ config PMIC_TPS65090 config PMIC_PALMAS bool "Enable driver for Texas Instruments PALMAS PMIC" - depends on DM_PMIC ---help--- The PALMAS is a PMIC containing several LDOs, SMPS. This driver binds the pmic children. config PMIC_LP873X bool "Enable driver for Texas Instruments LP873X PMIC" - depends on DM_PMIC ---help--- The LP873X is a PMIC containing couple of LDOs and couple of SMPS. This driver binds the pmic children. config PMIC_LP87565 bool "Enable driver for Texas Instruments LP87565 PMIC" - depends on DM_PMIC ---help--- The LP87565 is a PMIC containing a bunch of SMPS. This driver binds the pmic children. -config POWER_MC34VR500 - bool "Enable driver for Freescale MC34VR500 PMIC" - ---help--- - The MC34VR500 is used in conjunction with the FSL T1 and LS1 series - SoC. It provides 4 buck DC-DC convertors and 5 LDOs, and it is accessed - via an I2C interface. - config DM_PMIC_TPS65910 bool "Enable driver for Texas Instruments TPS65910 PMIC" - depends on DM_PMIC ---help--- The TPS65910 is a PMIC containing 3 buck DC-DC converters, one boost DC-DC converter, 8 LDOs and a RTC. This driver binds the SMPS and LDO @@ -330,7 +317,7 @@ config DM_PMIC_TPS65910 config PMIC_STPMIC1 bool "Enable support for STMicroelectronics STPMIC1 PMIC" - depends on DM_PMIC && DM_I2C + depends on DM_I2C select SYSRESET_CMD_POWEROFF if CMD_POWEROFF && !ARM_PSCI_FW ---help--- The STPMIC1 PMIC provides 4 BUCKs, 6 LDOs, 1 VREF and 2 power switches. @@ -339,28 +326,37 @@ config PMIC_STPMIC1 config SPL_PMIC_PALMAS bool "Enable driver for Texas Instruments PALMAS PMIC" - depends on DM_PMIC + depends on SPL_DM_PMIC help The PALMAS is a PMIC containing several LDOs, SMPS. This driver binds the pmic children in SPL. config SPL_PMIC_LP873X bool "Enable driver for Texas Instruments LP873X PMIC" - depends on DM_PMIC + depends on SPL_DM_PMIC help The LP873X is a PMIC containing couple of LDOs and couple of SMPS. This driver binds the pmic children in SPL. config SPL_PMIC_LP87565 bool "Enable driver for Texas Instruments LP87565 PMIC" - depends on DM_PMIC + depends on SPL_DM_PMIC help The LP87565 is a PMIC containing a bunch of SMPS. This driver binds the pmic children in SPL. config PMIC_TPS65941 bool "Enable driver for Texas Instruments TPS65941 PMIC" - depends on DM_PMIC help The TPS65941 is a PMIC containing a bunch of SMPS & LDOs. This driver binds the pmic children. + +endif + +config POWER_MC34VR500 + bool "Enable driver for Freescale MC34VR500 PMIC" + depends on !DM_PMIC + ---help--- + The MC34VR500 is used in conjunction with the FSL T1 and LS1 series + SoC. It provides 4 buck DC-DC convertors and 5 LDOs, and it is accessed + via an I2C interface. diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index 5250eac12f2..e1922df00f8 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o obj-$(CONFIG_PMIC_AB8500) += ab8500.o obj-$(CONFIG_PMIC_ACT8846) += act8846.o obj-$(CONFIG_PMIC_AS3722) += as3722.o as3722_gpio.o +obj-$(CONFIG_$(SPL_)PMIC_AXP) += axp.o obj-$(CONFIG_PMIC_MAX8997) += max8997.o obj-$(CONFIG_PMIC_PM8916) += pm8916.o obj-$(CONFIG_$(SPL_TPL_)PMIC_RK8XX) += rk8xx.o diff --git a/drivers/power/pmic/axp.c b/drivers/power/pmic/axp.c new file mode 100644 index 00000000000..74c94bdb47b --- /dev/null +++ b/drivers/power/pmic/axp.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> + +static int axp_pmic_reg_count(struct udevice *dev) +{ + /* TODO: Get the specific value from driver data. */ + return 0x100; +} + +static struct dm_pmic_ops axp_pmic_ops = { + .reg_count = axp_pmic_reg_count, + .read = dm_i2c_read, + .write = dm_i2c_write, +}; + +static const struct udevice_id axp_pmic_ids[] = { + { .compatible = "x-powers,axp152" }, + { .compatible = "x-powers,axp202" }, + { .compatible = "x-powers,axp209" }, + { .compatible = "x-powers,axp221" }, + { .compatible = "x-powers,axp223" }, + { .compatible = "x-powers,axp803" }, + { .compatible = "x-powers,axp806" }, + { .compatible = "x-powers,axp809" }, + { .compatible = "x-powers,axp813" }, + { } +}; + +U_BOOT_DRIVER(axp_pmic) = { + .name = "axp_pmic", + .id = UCLASS_PMIC, + .of_match = axp_pmic_ids, + .bind = dm_scan_fdt_dev, + .ops = &axp_pmic_ops, +}; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index cf7f4c6840c..669d3fa4fc5 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -9,6 +9,12 @@ config DM_PWM frequency/period can be controlled along with the proportion of that time that the signal is high. +config PWM_AT91 + bool "Enable support for PWM found on AT91 SoC's" + depends on DM_PWM && ARCH_AT91 + help + Support for PWM hardware on AT91 based SoC. + config PWM_CROS_EC bool "Enable support for the Chrome OS EC PWM" depends on DM_PWM diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 10d244bfb79..55f2bc081d2 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_DM_PWM) += pwm-uclass.o +obj-$(CONFIG_PWM_AT91) += pwm-at91.o obj-$(CONFIG_PWM_CROS_EC) += cros_ec_pwm.o obj-$(CONFIG_PWM_EXYNOS) += exynos_pwm.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o pwm-imx-util.o diff --git a/drivers/pwm/pwm-at91.c b/drivers/pwm/pwm-at91.c new file mode 100644 index 00000000000..95597aee557 --- /dev/null +++ b/drivers/pwm/pwm-at91.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * PWM support for Microchip AT91 architectures. + * + * Copyright (C) 2021 Microchip Technology Inc. and its subsidiaries + * + * Author: Dan Sneddon <daniel.sneddon@microchip.com> + * + * Based on drivers/pwm/pwm-atmel.c from Linux. + */ +#include <clk.h> +#include <common.h> +#include <div64.h> +#include <dm.h> +#include <linux/bitops.h> +#include <linux/io.h> +#include <pwm.h> + +#define PERIOD_BITS 16 +#define PWM_MAX_PRES 10 +#define NSEC_PER_SEC 1000000000L + +#define PWM_ENA 0x04 +#define PWM_CHANNEL_OFFSET 0x20 +#define PWM_CMR 0x200 +#define PWM_CMR_CPRE_MSK GENMASK(3, 0) +#define PWM_CMR_CPOL BIT(9) +#define PWM_CDTY 0x204 +#define PWM_CPRD 0x20C + +struct at91_pwm_priv { + void __iomem *base; + struct clk pclk; + u32 clkrate; +}; + +static int at91_pwm_calculate_cprd_and_pres(struct udevice *dev, + unsigned long clkrate, + uint period_ns, uint duty_ns, + unsigned long *cprd, u32 *pres) +{ + u64 cycles = period_ns; + int shift; + + /* Calculate the period cycles and prescale value */ + cycles *= clkrate; + do_div(cycles, NSEC_PER_SEC); + + /* + * The register for the period length is period_bits bits wide. + * So for each bit the number of clock cycles is wider divide the input + * clock frequency by two using pres and shift cprd accordingly. + */ + shift = fls(cycles) - PERIOD_BITS; + + if (shift > PWM_MAX_PRES) { + return -EINVAL; + } else if (shift > 0) { + *pres = shift; + cycles >>= *pres; + } else { + *pres = 0; + } + + *cprd = cycles; + + return 0; +} + +static void at91_pwm_calculate_cdty(uint period_ns, uint duty_ns, + unsigned long clkrate, unsigned long cprd, + u32 pres, unsigned long *cdty) +{ + u64 cycles = duty_ns; + + cycles *= clkrate; + do_div(cycles, NSEC_PER_SEC); + cycles >>= pres; + *cdty = cprd - cycles; +} + +/** + * Returns: channel status after set operation + */ +static bool at91_pwm_set(void __iomem *base, uint channel, bool enable) +{ + u32 val, cur_status; + + val = ioread32(base + PWM_ENA); + cur_status = !!(val & BIT(channel)); + + /* if channel is already in that state, do nothing */ + if (!(enable ^ cur_status)) + return cur_status; + + if (enable) + val |= BIT(channel); + else + val &= ~(BIT(channel)); + + iowrite32(val, base + PWM_ENA); + + return cur_status; +} + +static int at91_pwm_set_enable(struct udevice *dev, uint channel, bool enable) +{ + struct at91_pwm_priv *priv = dev_get_priv(dev); + + at91_pwm_set(priv->base, channel, enable); + + return 0; +} + +static int at91_pwm_set_config(struct udevice *dev, uint channel, + uint period_ns, uint duty_ns) +{ + struct at91_pwm_priv *priv = dev_get_priv(dev); + unsigned long cprd, cdty; + u32 pres, val; + int channel_enabled; + int ret; + + ret = at91_pwm_calculate_cprd_and_pres(dev, priv->clkrate, period_ns, + duty_ns, &cprd, &pres); + if (ret) + return ret; + + at91_pwm_calculate_cdty(period_ns, duty_ns, priv->clkrate, cprd, pres, &cdty); + + /* disable the channel */ + channel_enabled = at91_pwm_set(priv->base, channel, false); + + /* It is necessary to preserve CPOL, inside CMR */ + val = ioread32(priv->base + (channel * PWM_CHANNEL_OFFSET) + PWM_CMR); + val = (val & ~PWM_CMR_CPRE_MSK) | (pres & PWM_CMR_CPRE_MSK); + iowrite32(val, priv->base + (channel * PWM_CHANNEL_OFFSET) + PWM_CMR); + + iowrite32(cprd, priv->base + (channel * PWM_CHANNEL_OFFSET) + PWM_CPRD); + + iowrite32(cdty, priv->base + (channel * PWM_CHANNEL_OFFSET) + PWM_CDTY); + + /* renable the channel if needed */ + if (channel_enabled) + at91_pwm_set(priv->base, channel, true); + + return 0; +} + +static int at91_pwm_set_invert(struct udevice *dev, uint channel, + bool polarity) +{ + struct at91_pwm_priv *priv = dev_get_priv(dev); + u32 val; + + val = ioread32(priv->base + (channel * PWM_CHANNEL_OFFSET) + PWM_CMR); + if (polarity) + val |= PWM_CMR_CPOL; + else + val &= ~PWM_CMR_CPOL; + iowrite32(val, priv->base + (channel * PWM_CHANNEL_OFFSET) + PWM_CMR); + + return 0; +} + +static int at91_pwm_probe(struct udevice *dev) +{ + struct at91_pwm_priv *priv = dev_get_priv(dev); + int ret; + + priv->base = dev_read_addr_ptr(dev); + if (!priv->base) + return -EINVAL; + + ret = clk_get_by_index(dev, 0, &priv->pclk); + if (ret) + return ret; + + /* clocks aren't ref-counted so just enabled them once here */ + ret = clk_enable(&priv->pclk); + if (ret) + return ret; + + priv->clkrate = clk_get_rate(&priv->pclk); + + return ret; +} + +static const struct pwm_ops at91_pwm_ops = { + .set_config = at91_pwm_set_config, + .set_enable = at91_pwm_set_enable, + .set_invert = at91_pwm_set_invert, +}; + +static const struct udevice_id at91_pwm_of_match[] = { + { .compatible = "atmel,sama5d2-pwm" }, + { } +}; + +U_BOOT_DRIVER(at91_pwm) = { + .name = "at91_pwm", + .id = UCLASS_PWM, + .of_match = at91_pwm_of_match, + .probe = at91_pwm_probe, + .priv_auto = sizeof(struct at91_pwm_priv), + .ops = &at91_pwm_ops, +}; diff --git a/drivers/ram/sifive/sifive_ddr.c b/drivers/ram/sifive/sifive_ddr.c index ba184660331..4bd69a62be2 100644 --- a/drivers/ram/sifive/sifive_ddr.c +++ b/drivers/ram/sifive/sifive_ddr.c @@ -313,7 +313,7 @@ static int sifive_ddr_setup(struct udevice *dev) sifive_ddr_phy_fixup(denali_phy); /* check size */ - priv->info.size = get_ram_size((long *)priv->info.base, + priv->info.size = get_ram_size((long *)(uintptr_t)priv->info.base, ddr_size); debug("%s : %lx\n", __func__, (uintptr_t)priv->info.size); @@ -369,9 +369,9 @@ static int sifive_ddr_probe(struct udevice *dev) return ret; } - priv->ctl = (struct sifive_ddrctl *)dev_read_addr_index(dev, 0); - priv->phy = (struct sifive_ddrphy *)dev_read_addr_index(dev, 1); - priv->physical_filter_ctrl = (u32 *)dev_read_addr_index(dev, 2); + priv->ctl = (struct sifive_ddrctl *)dev_read_addr_index_ptr(dev, 0); + priv->phy = (struct sifive_ddrphy *)dev_read_addr_index_ptr(dev, 1); + priv->physical_filter_ctrl = (u32 *)dev_read_addr_index_ptr(dev, 2); return sifive_ddr_setup(dev); #endif diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c index 264337ed803..8b95938dfe3 100644 --- a/drivers/reset/reset-sunxi.c +++ b/drivers/reset/reset-sunxi.c @@ -11,11 +11,11 @@ #include <malloc.h> #include <reset-uclass.h> #include <asm/io.h> +#include <clk/sunxi.h> #include <dm/device-internal.h> #include <dm/lists.h> #include <linux/bitops.h> #include <linux/log2.h> -#include <asm/arch/ccu.h> struct sunxi_reset_priv { void *base; diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c index 3be97c9d933..1963565c5ee 100644 --- a/drivers/rtc/ds1307.c +++ b/drivers/rtc/ds1307.c @@ -41,6 +41,12 @@ enum ds_type { #define RTC_YR_REG_ADDR 0x06 #define RTC_CTL_REG_ADDR 0x07 +#define DS1337_CTL_REG_ADDR 0x0e +#define DS1337_STAT_REG_ADDR 0x0f +#define DS1340_STAT_REG_ADDR 0x09 + +#define RTC_STAT_BIT_OSF 0x80 + #define RTC_SEC_BIT_CH 0x80 /* Clock Halt (in Register 0) */ /* DS1307-specific bits */ @@ -248,6 +254,11 @@ static int ds1307_rtc_set(struct udevice *dev, const struct rtc_time *tm) if (ret < 0) return ret; + if (type == ds_1337) { + /* Ensure oscillator is enabled */ + dm_i2c_reg_write(dev, DS1337_CTL_REG_ADDR, 0); + } + return 0; } @@ -257,62 +268,19 @@ static int ds1307_rtc_get(struct udevice *dev, struct rtc_time *tm) uchar buf[7]; enum ds_type type = dev_get_driver_data(dev); -read_rtc: ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); if (ret < 0) return ret; - if (type == ds_1307) { - if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) { - printf("### Warning: RTC oscillator has stopped\n"); - /* clear the CH flag */ - buf[RTC_SEC_REG_ADDR] &= ~RTC_SEC_BIT_CH; - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, - buf[RTC_SEC_REG_ADDR]); - return -1; - } - } else if (type == ds_1337) { - if (buf[RTC_CTL_REG_ADDR] & DS1337_CTL_BIT_EOSC) { - printf("### Warning: RTC oscillator has stopped\n"); - /* clear the not oscillator enable (~EOSC) flag */ - buf[RTC_CTL_REG_ADDR] &= ~DS1337_CTL_BIT_EOSC; - dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, - buf[RTC_CTL_REG_ADDR]); - return -1; - } - } else if (type == ds_1340) { - if (buf[RTC_SEC_REG_ADDR] & DS1340_SEC_BIT_EOSC) { - printf("### Warning: RTC oscillator has stopped\n"); - /* clear the not oscillator enable (~EOSC) flag */ - buf[RTC_SEC_REG_ADDR] &= ~DS1340_SEC_BIT_EOSC; - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, - buf[RTC_SEC_REG_ADDR]); - return -1; - } - } else if (type == m41t11) { - /* clock halted? turn it on, so clock can tick. */ - if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) { - buf[RTC_SEC_REG_ADDR] &= ~RTC_SEC_BIT_CH; - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, - MCP7941X_BIT_ST); - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, - buf[RTC_SEC_REG_ADDR]); - goto read_rtc; - } - } else if (type == mcp794xx) { - /* make sure that the backup battery is enabled */ - if (!(buf[RTC_DAY_REG_ADDR] & MCP7941X_BIT_VBATEN)) { - dm_i2c_reg_write(dev, RTC_DAY_REG_ADDR, - buf[RTC_DAY_REG_ADDR] | - MCP7941X_BIT_VBATEN); - } + if (type == ds_1337 || type == ds_1340) { + uint reg = (type == ds_1337) ? DS1337_STAT_REG_ADDR : + DS1340_STAT_REG_ADDR; + int status = dm_i2c_reg_read(dev, reg); - /* clock halted? turn it on, so clock can tick. */ - if (!(buf[RTC_SEC_REG_ADDR] & MCP7941X_BIT_ST)) { - dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, - MCP7941X_BIT_ST); - printf("Started RTC\n"); - goto read_rtc; + if (status >= 0 && (status & RTC_STAT_BIT_OSF)) { + printf("### Warning: RTC oscillator has stopped\n"); + /* clear the OSF flag */ + dm_i2c_reg_write(dev, reg, status & ~RTC_STAT_BIT_OSF); } } @@ -361,7 +329,7 @@ static int ds1307_rtc_reset(struct udevice *dev) /* Write control register in order to enable oscillator output * (not EOSC) and set a default rate of 32.768kHz (RS2|RS1). */ - ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR, + ret = dm_i2c_reg_write(dev, DS1337_CTL_REG_ADDR, DS1337_CTL_BIT_RS2 | DS1337_CTL_BIT_RS1); } else if (type == ds_1340 || type == mcp794xx || type == m41t11) { /* Reset clock calibration, frequency test and output level. */ diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 3bb5b02eabb..122a39789cb 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -280,6 +280,14 @@ config DEBUG_EFI_CONSOLE U-Boot when running on top of EFI (Extensive Firmware Interface). This is a type of BIOS used by PCs. +config DEBUG_SBI_CONSOLE + bool "SBI" + depends on SBI_V01 + help + Select this to enable a debug console which calls back to SBI to + output to the console. This can be useful for early debugging of + U-Boot when running on top of SBI (Supervisor Binary Interface). + config DEBUG_UART_S5P bool "Samsung S5P" depends on ARCH_EXYNOS || ARCH_S5PC1XX @@ -442,6 +450,7 @@ endchoice config DEBUG_UART_BASE hex "Base address of UART" depends on DEBUG_UART + default 0 if DEBUG_SBI_CONSOLE default 0 if DEBUG_UART_SANDBOX help This is the base address of your UART for memory-mapped UARTs. @@ -452,6 +461,7 @@ config DEBUG_UART_BASE config DEBUG_UART_CLOCK int "UART input clock" depends on DEBUG_UART + default 0 if DEBUG_SBI_CONSOLE default 0 if DEBUG_UART_SANDBOX default 0 if DEBUG_MVEBU_A3700_UART help diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 3cbea8156f8..4edd2aa9458 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_ATMEL_USART) += atmel_usart.o obj-$(CONFIG_BCM6345_SERIAL) += serial_bcm6345.o obj-$(CONFIG_COREBOOT_SERIAL) += serial_coreboot.o obj-$(CONFIG_CORTINA_UART) += serial_cortina.o +obj-$(CONFIG_DEBUG_SBI_CONSOLE) += serial_sbi.o obj-$(CONFIG_EFI_APP) += serial_efi.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += serial_mcf.o diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 57a78484415..30d44214d7d 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -65,7 +65,7 @@ static int serial_check_stdout(const void *blob, struct udevice **devp) * anyway. */ if (node > 0 && !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node), - devp, false)) { + devp, NULL, false)) { if (!device_probe(*devp)) return 0; } diff --git a/drivers/serial/serial_sbi.c b/drivers/serial/serial_sbi.c new file mode 100644 index 00000000000..b9f35ed36e6 --- /dev/null +++ b/drivers/serial/serial_sbi.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <debug_uart.h> +#include <asm/sbi.h> + +static inline void _debug_uart_init(void) +{ +} + +static inline void _debug_uart_putc(int c) +{ + if (CONFIG_IS_ENABLED(RISCV_SMODE)) + sbi_console_putchar(c); +} + +DEBUG_UART_FUNCS diff --git a/drivers/spi/rockchip_sfc.c b/drivers/spi/rockchip_sfc.c index 4e2b861f224..e098addddca 100644 --- a/drivers/spi/rockchip_sfc.c +++ b/drivers/spi/rockchip_sfc.c @@ -116,6 +116,7 @@ /* Master trigger */ #define SFC_DMA_TRIGGER 0x80 +#define SFC_DMA_TRIGGER_START 1 /* Src or Dst addr for master */ #define SFC_DMA_ADDR 0x84 @@ -163,14 +164,12 @@ #define SFC_DMA_TRANS_THRETHOLD (0x40) /* Maximum clock values from datasheet suggest keeping clock value under - * 150MHz. No minimum or average value is suggested, but the U-boot BSP driver - * has a minimum of 10MHz and a default of 80MHz which seems reasonable. + * 150MHz. No minimum or average value is suggested. */ -#define SFC_MIN_SPEED_HZ (10 * 1000 * 1000) -#define SFC_DEFAULT_SPEED_HZ (80 * 1000 * 1000) -#define SFC_MAX_SPEED_HZ (150 * 1000 * 1000) +#define SFC_MAX_SPEED (150 * 1000 * 1000) struct rockchip_sfc { + struct udevice *dev; void __iomem *regbase; struct clk hclk; struct clk clk; @@ -197,8 +196,6 @@ static int rockchip_sfc_reset(struct rockchip_sfc *sfc) /* Still need to clear the masked interrupt from RISR */ writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR); - debug("reset\n"); - return err; } @@ -261,15 +258,11 @@ static int rockchip_sfc_probe(struct udevice *bus) #if CONFIG_IS_ENABLED(CLK) ret = clk_enable(&sfc->hclk); if (ret) - debug("Enable ahb clock fail %s: %d\n", bus->name, ret); + dev_dbg(sfc->dev, "sfc Enable ahb clock fail %s: %d\n", bus->name, ret); ret = clk_enable(&sfc->clk); if (ret) - debug("Enable clock fail for %s: %d\n", bus->name, ret); - - ret = clk_set_rate(&sfc->clk, SFC_DEFAULT_SPEED_HZ); - if (ret) - debug("Could not set sfc clock for %s: %d\n", bus->name, ret); + dev_dbg(sfc->dev, "sfc Enable clock fail for %s: %d\n", bus->name, ret); #endif ret = rockchip_sfc_init(sfc); @@ -278,7 +271,8 @@ static int rockchip_sfc_probe(struct udevice *bus) sfc->max_iosize = rockchip_sfc_get_max_iosize(sfc); sfc->version = rockchip_sfc_get_version(sfc); - sfc->speed = SFC_DEFAULT_SPEED_HZ; + sfc->max_freq = SFC_MAX_SPEED; + sfc->dev = bus; return 0; @@ -291,33 +285,38 @@ err_init: return ret; } -static inline int rockchip_sfc_get_fifo_level(struct rockchip_sfc *sfc, int wr) +static int rockchip_sfc_wait_txfifo_ready(struct rockchip_sfc *sfc, u32 timeout_us) { - u32 fsr = readl(sfc->regbase + SFC_FSR); - int level; + int ret = 0; + u32 status; - if (wr) - level = (fsr & SFC_FSR_TXLV_MASK) >> SFC_FSR_TXLV_SHIFT; - else - level = (fsr & SFC_FSR_RXLV_MASK) >> SFC_FSR_RXLV_SHIFT; + ret = readl_poll_timeout(sfc->regbase + SFC_FSR, status, + status & SFC_FSR_TXLV_MASK, + timeout_us); + if (ret) { + dev_dbg(sfc->dev, "sfc wait tx fifo timeout\n"); + + return -ETIMEDOUT; + } - return level; + return (status & SFC_FSR_TXLV_MASK) >> SFC_FSR_TXLV_SHIFT; } -static int rockchip_sfc_wait_fifo_ready(struct rockchip_sfc *sfc, int wr, u32 timeout) +static int rockchip_sfc_wait_rxfifo_ready(struct rockchip_sfc *sfc, u32 timeout_us) { - unsigned long tbase = get_timer(0); - int level; + int ret = 0; + u32 status; - while (!(level = rockchip_sfc_get_fifo_level(sfc, wr))) { - if (get_timer(tbase) > timeout) { - debug("%s fifo timeout\n", wr ? "write" : "read"); - return -ETIMEDOUT; - } - udelay(1); + ret = readl_poll_timeout(sfc->regbase + SFC_FSR, status, + status & SFC_FSR_RXLV_MASK, + timeout_us); + if (ret) { + dev_dbg(sfc->dev, "sfc wait rx fifo timeout\n"); + + return -ETIMEDOUT; } - return level; + return (status & SFC_FSR_RXLV_MASK) >> SFC_FSR_RXLV_SHIFT; } static void rockchip_sfc_adjust_op_work(struct spi_mem_op *op) @@ -411,11 +410,11 @@ static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc, ctrl |= SFC_CTRL_PHASE_SEL_NEGETIVE; cmd |= plat->cs << SFC_CMD_CS_SHIFT; - debug("addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n", - op->addr.nbytes, op->addr.buswidth, - op->dummy.nbytes, op->dummy.buswidth); - debug("ctrl=%x cmd=%x addr=%llx len=%x\n", - ctrl, cmd, op->addr.val, len); + dev_dbg(sfc->dev, "sfc addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n", + op->addr.nbytes, op->addr.buswidth, + op->dummy.nbytes, op->dummy.buswidth); + dev_dbg(sfc->dev, "sfc ctrl=%x cmd=%x addr=%llx len=%x\n", + ctrl, cmd, op->addr.val, len); writel(ctrl, sfc->regbase + SFC_CTRL); writel(cmd, sfc->regbase + SFC_CMD); @@ -435,7 +434,7 @@ static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, const u8 *buf, int dwords = len >> 2; while (dwords) { - tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_WR, 1000); + tx_level = rockchip_sfc_wait_txfifo_ready(sfc, 1000); if (tx_level < 0) return tx_level; write_words = min_t(u32, tx_level, dwords); @@ -446,7 +445,7 @@ static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, const u8 *buf, int /* write the rest non word aligned bytes */ if (bytes) { - tx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_WR, 1000); + tx_level = rockchip_sfc_wait_txfifo_ready(sfc, 1000); if (tx_level < 0) return tx_level; memcpy(&tmp, buf, bytes); @@ -467,7 +466,7 @@ static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u8 *buf, int len) /* word aligned access only */ dwords = len >> 2; while (dwords) { - rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_RD, 1000); + rx_level = rockchip_sfc_wait_rxfifo_ready(sfc, 1000); if (rx_level < 0) return rx_level; read_words = min_t(u32, rx_level, dwords); @@ -478,7 +477,7 @@ static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u8 *buf, int len) /* read the rest non word aligned bytes */ if (bytes) { - rx_level = rockchip_sfc_wait_fifo_ready(sfc, SFC_CMD_DIR_RD, 1000); + rx_level = rockchip_sfc_wait_rxfifo_ready(sfc, 1000); if (rx_level < 0) return rx_level; tmp = readl(sfc->regbase + SFC_DATA); @@ -492,7 +491,7 @@ static int rockchip_sfc_fifo_transfer_dma(struct rockchip_sfc *sfc, dma_addr_t d { writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR); writel((u32)dma_buf, sfc->regbase + SFC_DMA_ADDR); - writel(0x1, sfc->regbase + SFC_DMA_TRIGGER); + writel(SFC_DMA_TRIGGER_START, sfc->regbase + SFC_DMA_TRIGGER); return len; } @@ -500,7 +499,7 @@ static int rockchip_sfc_fifo_transfer_dma(struct rockchip_sfc *sfc, dma_addr_t d static int rockchip_sfc_xfer_data_poll(struct rockchip_sfc *sfc, const struct spi_mem_op *op, u32 len) { - debug("xfer_poll len=%x\n", len); + dev_dbg(sfc->dev, "sfc xfer_poll len=%x\n", len); if (op->data.dir == SPI_MEM_DATA_OUT) return rockchip_sfc_write_fifo(sfc, op->data.buf.out, len); @@ -516,7 +515,7 @@ static int rockchip_sfc_xfer_data_dma(struct rockchip_sfc *sfc, void *dma_buf; int ret; - debug("xfer_dma len=%x\n", len); + dev_dbg(sfc->dev, "sfc xfer_dma len=%x\n", len); if (op->data.dir == SPI_MEM_DATA_OUT) { dma_buf = (void *)op->data.buf.out; @@ -539,19 +538,17 @@ static int rockchip_sfc_xfer_data_dma(struct rockchip_sfc *sfc, static int rockchip_sfc_xfer_done(struct rockchip_sfc *sfc, u32 timeout_us) { - unsigned long tbase = get_timer(0); int ret = 0; - u32 timeout = timeout_us; - - while (readl(sfc->regbase + SFC_SR) & SFC_SR_IS_BUSY) { - if (get_timer(tbase) > timeout) { - printf("wait sfc idle timeout\n"); - rockchip_sfc_reset(sfc); + u32 status; - return -ETIMEDOUT; - } + ret = readl_poll_timeout(sfc->regbase + SFC_SR, status, + !(status & SFC_SR_IS_BUSY), + timeout_us); + if (ret) { + dev_err(sfc->dev, "wait sfc idle timeout\n"); + rockchip_sfc_reset(sfc); - udelay(1); + ret = -EIO; } return ret; @@ -564,33 +561,16 @@ static int rockchip_sfc_exec_op(struct spi_slave *mem, u32 len = min_t(u32, op->data.nbytes, sfc->max_iosize); int ret; -#if CONFIG_IS_ENABLED(CLK) - if (unlikely(mem->max_hz != sfc->speed)) { - ret = clk_set_rate(&sfc->clk, clamp(mem->max_hz, (uint)SFC_MIN_SPEED_HZ, - (uint)SFC_MAX_SPEED_HZ)); - if (ret < 0) { - printf("set_freq=%dHz fail, check if it's the cru support level\n", - mem->max_hz); - return ret; - } - - sfc->max_freq = mem->max_hz; - sfc->speed = mem->max_hz; - debug("set_freq=%dHz real_freq=%dHz\n", sfc->max_freq, sfc->speed); - } -#endif - rockchip_sfc_adjust_op_work((struct spi_mem_op *)op); - rockchip_sfc_xfer_setup(sfc, mem, op, len); if (len) { - if (likely(sfc->use_dma) && !(len & 0x3) && len >= SFC_DMA_TRANS_THRETHOLD) + if (likely(sfc->use_dma) && len >= SFC_DMA_TRANS_THRETHOLD) ret = rockchip_sfc_xfer_data_dma(sfc, op, len); else ret = rockchip_sfc_xfer_data_poll(sfc, op, len); if (ret != len) { - printf("xfer data failed ret %d dir %d\n", ret, op->data.dir); + dev_err(sfc->dev, "xfer data failed ret %d dir %d\n", ret, op->data.dir); return -EIO; } @@ -604,13 +584,32 @@ static int rockchip_sfc_adjust_op_size(struct spi_slave *mem, struct spi_mem_op struct rockchip_sfc *sfc = dev_get_plat(mem->dev->parent); op->data.nbytes = min(op->data.nbytes, sfc->max_iosize); + return 0; } static int rockchip_sfc_set_speed(struct udevice *bus, uint speed) { - /* We set up speed later for each transmission. - */ + struct rockchip_sfc *sfc = dev_get_plat(bus); + + if (speed > sfc->max_freq) + speed = sfc->max_freq; + + if (speed == sfc->speed) + return 0; + +#if CONFIG_IS_ENABLED(CLK) + int ret = clk_set_rate(&sfc->clk, speed); + + if (ret < 0) { + dev_err(sfc->dev, "set_freq=%dHz fail, check if it's the cru support level\n", + speed); + return ret; + } + sfc->speed = speed; +#else + dev_dbg(sfc->dev, "sfc failed, CLK not support\n"); +#endif return 0; } diff --git a/drivers/spi/spi-sunxi.c b/drivers/spi/spi-sunxi.c index 4ca5d3a93ac..bc2f544e863 100644 --- a/drivers/spi/spi-sunxi.c +++ b/drivers/spi/spi-sunxi.c @@ -245,7 +245,7 @@ static int sun4i_spi_parse_pins(struct udevice *dev) break; } - pin = name_to_gpio(pin_name); + pin = sunxi_name_to_gpio(pin_name); if (pin < 0) break; diff --git a/drivers/spi/stm32_spi.c b/drivers/spi/stm32_spi.c index bd8514033de..fe5419e8518 100644 --- a/drivers/spi/stm32_spi.c +++ b/drivers/spi/stm32_spi.c @@ -97,11 +97,14 @@ #define SPI_SIMPLEX_RX 2 #define SPI_HALF_DUPLEX 3 -struct stm32_spi_priv { +struct stm32_spi_plat { void __iomem *base; struct clk clk; struct reset_ctl rst_ctl; struct gpio_desc cs_gpios[MAX_CS_COUNT]; +}; + +struct stm32_spi_priv { ulong bus_clk_rate; unsigned int fifo_size; unsigned int cur_bpw; @@ -115,28 +118,32 @@ struct stm32_spi_priv { bool cs_high; }; -static void stm32_spi_write_txfifo(struct stm32_spi_priv *priv) +static void stm32_spi_write_txfifo(struct udevice *bus) { + struct stm32_spi_priv *priv = dev_get_priv(bus); + struct stm32_spi_plat *plat = dev_get_plat(bus); + void __iomem *base = plat->base; + while ((priv->tx_len > 0) && - (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP)) { + (readl(base + STM32_SPI_SR) & SPI_SR_TXP)) { u32 offs = priv->cur_xferlen - priv->tx_len; if (priv->tx_len >= sizeof(u32) && IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u32))) { const u32 *tx_buf32 = (const u32 *)(priv->tx_buf + offs); - writel(*tx_buf32, priv->base + STM32_SPI_TXDR); + writel(*tx_buf32, base + STM32_SPI_TXDR); priv->tx_len -= sizeof(u32); } else if (priv->tx_len >= sizeof(u16) && IS_ALIGNED((uintptr_t)(priv->tx_buf + offs), sizeof(u16))) { const u16 *tx_buf16 = (const u16 *)(priv->tx_buf + offs); - writew(*tx_buf16, priv->base + STM32_SPI_TXDR); + writew(*tx_buf16, base + STM32_SPI_TXDR); priv->tx_len -= sizeof(u16); } else { const u8 *tx_buf8 = (const u8 *)(priv->tx_buf + offs); - writeb(*tx_buf8, priv->base + STM32_SPI_TXDR); + writeb(*tx_buf8, base + STM32_SPI_TXDR); priv->tx_len -= sizeof(u8); } } @@ -144,9 +151,12 @@ static void stm32_spi_write_txfifo(struct stm32_spi_priv *priv) log_debug("%d bytes left\n", priv->tx_len); } -static void stm32_spi_read_rxfifo(struct stm32_spi_priv *priv) +static void stm32_spi_read_rxfifo(struct udevice *bus) { - u32 sr = readl(priv->base + STM32_SPI_SR); + struct stm32_spi_priv *priv = dev_get_priv(bus); + struct stm32_spi_plat *plat = dev_get_plat(bus); + void __iomem *base = plat->base; + u32 sr = readl(base + STM32_SPI_SR); u32 rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; while ((priv->rx_len > 0) && @@ -158,7 +168,7 @@ static void stm32_spi_read_rxfifo(struct stm32_spi_priv *priv) (priv->rx_len >= sizeof(u32) || (sr & SPI_SR_RXWNE))) { u32 *rx_buf32 = (u32 *)(priv->rx_buf + offs); - *rx_buf32 = readl(priv->base + STM32_SPI_RXDR); + *rx_buf32 = readl(base + STM32_SPI_RXDR); priv->rx_len -= sizeof(u32); } else if (IS_ALIGNED((uintptr_t)(priv->rx_buf + offs), sizeof(u16)) && (priv->rx_len >= sizeof(u16) || @@ -166,38 +176,38 @@ static void stm32_spi_read_rxfifo(struct stm32_spi_priv *priv) (rxplvl >= 2 || priv->cur_bpw > 8)))) { u16 *rx_buf16 = (u16 *)(priv->rx_buf + offs); - *rx_buf16 = readw(priv->base + STM32_SPI_RXDR); + *rx_buf16 = readw(base + STM32_SPI_RXDR); priv->rx_len -= sizeof(u16); } else { u8 *rx_buf8 = (u8 *)(priv->rx_buf + offs); - *rx_buf8 = readb(priv->base + STM32_SPI_RXDR); + *rx_buf8 = readb(base + STM32_SPI_RXDR); priv->rx_len -= sizeof(u8); } - sr = readl(priv->base + STM32_SPI_SR); + sr = readl(base + STM32_SPI_SR); rxplvl = (sr & SPI_SR_RXPLVL) >> SPI_SR_RXPLVL_SHIFT; } log_debug("%d bytes left\n", priv->rx_len); } -static int stm32_spi_enable(struct stm32_spi_priv *priv) +static int stm32_spi_enable(void __iomem *base) { log_debug("\n"); /* Enable the SPI hardware */ - setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); + setbits_le32(base + STM32_SPI_CR1, SPI_CR1_SPE); return 0; } -static int stm32_spi_disable(struct stm32_spi_priv *priv) +static int stm32_spi_disable(void __iomem *base) { log_debug("\n"); /* Disable the SPI hardware */ - clrbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_SPE); + clrbits_le32(base + STM32_SPI_CR1, SPI_CR1_SPE); return 0; } @@ -205,45 +215,48 @@ static int stm32_spi_disable(struct stm32_spi_priv *priv) static int stm32_spi_claim_bus(struct udevice *slave) { struct udevice *bus = dev_get_parent(slave); - struct stm32_spi_priv *priv = dev_get_priv(bus); + struct stm32_spi_plat *plat = dev_get_plat(bus); + void __iomem *base = plat->base; dev_dbg(slave, "\n"); /* Enable the SPI hardware */ - return stm32_spi_enable(priv); + return stm32_spi_enable(base); } static int stm32_spi_release_bus(struct udevice *slave) { struct udevice *bus = dev_get_parent(slave); - struct stm32_spi_priv *priv = dev_get_priv(bus); + struct stm32_spi_plat *plat = dev_get_plat(bus); + void __iomem *base = plat->base; dev_dbg(slave, "\n"); /* Disable the SPI hardware */ - return stm32_spi_disable(priv); + return stm32_spi_disable(base); } static void stm32_spi_stopxfer(struct udevice *dev) { - struct stm32_spi_priv *priv = dev_get_priv(dev); + struct stm32_spi_plat *plat = dev_get_plat(dev); + void __iomem *base = plat->base; u32 cr1, sr; int ret; dev_dbg(dev, "\n"); - cr1 = readl(priv->base + STM32_SPI_CR1); + cr1 = readl(base + STM32_SPI_CR1); if (!(cr1 & SPI_CR1_SPE)) return; /* Wait on EOT or suspend the flow */ - ret = readl_poll_timeout(priv->base + STM32_SPI_SR, sr, + ret = readl_poll_timeout(base + STM32_SPI_SR, sr, !(sr & SPI_SR_EOT), 100000); if (ret < 0) { if (cr1 & SPI_CR1_CSTART) { - writel(cr1 | SPI_CR1_CSUSP, priv->base + STM32_SPI_CR1); - if (readl_poll_timeout(priv->base + STM32_SPI_SR, + writel(cr1 | SPI_CR1_CSUSP, base + STM32_SPI_CR1); + if (readl_poll_timeout(base + STM32_SPI_SR, sr, !(sr & SPI_SR_SUSP), 100000) < 0) dev_err(dev, "Suspend request timeout\n"); @@ -251,11 +264,12 @@ static void stm32_spi_stopxfer(struct udevice *dev) } /* clear status flags */ - setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); + setbits_le32(base + STM32_SPI_IFCR, SPI_IFCR_ALL); } static int stm32_spi_set_cs(struct udevice *dev, unsigned int cs, bool enable) { + struct stm32_spi_plat *plat = dev_get_plat(dev); struct stm32_spi_priv *priv = dev_get_priv(dev); dev_dbg(dev, "cs=%d enable=%d\n", cs, enable); @@ -263,18 +277,20 @@ static int stm32_spi_set_cs(struct udevice *dev, unsigned int cs, bool enable) if (cs >= MAX_CS_COUNT) return -ENODEV; - if (!dm_gpio_is_valid(&priv->cs_gpios[cs])) + if (!dm_gpio_is_valid(&plat->cs_gpios[cs])) return -EINVAL; if (priv->cs_high) enable = !enable; - return dm_gpio_set_value(&priv->cs_gpios[cs], enable ? 1 : 0); + return dm_gpio_set_value(&plat->cs_gpios[cs], enable ? 1 : 0); } static int stm32_spi_set_mode(struct udevice *bus, uint mode) { struct stm32_spi_priv *priv = dev_get_priv(bus); + struct stm32_spi_plat *plat = dev_get_plat(bus); + void __iomem *base = plat->base; u32 cfg2_clrb = 0, cfg2_setb = 0; dev_dbg(bus, "mode=%d\n", mode); @@ -295,7 +311,7 @@ static int stm32_spi_set_mode(struct udevice *bus, uint mode) cfg2_clrb |= SPI_CFG2_LSBFRST; if (cfg2_clrb || cfg2_setb) - clrsetbits_le32(priv->base + STM32_SPI_CFG2, + clrsetbits_le32(base + STM32_SPI_CFG2, cfg2_clrb, cfg2_setb); if (mode & SPI_CS_HIGH) @@ -308,6 +324,8 @@ static int stm32_spi_set_mode(struct udevice *bus, uint mode) static int stm32_spi_set_fthlv(struct udevice *dev, u32 xfer_len) { struct stm32_spi_priv *priv = dev_get_priv(dev); + struct stm32_spi_plat *plat = dev_get_plat(dev); + void __iomem *base = plat->base; u32 fthlv, half_fifo; /* data packet should not exceed 1/2 of fifo space */ @@ -321,7 +339,7 @@ static int stm32_spi_set_fthlv(struct udevice *dev, u32 xfer_len) if (!fthlv) fthlv = 1; - clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_FTHLV, + clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_FTHLV, (fthlv - 1) << SPI_CFG1_FTHLV_SHIFT); return 0; @@ -330,6 +348,8 @@ static int stm32_spi_set_fthlv(struct udevice *dev, u32 xfer_len) static int stm32_spi_set_speed(struct udevice *bus, uint hz) { struct stm32_spi_priv *priv = dev_get_priv(bus); + struct stm32_spi_plat *plat = dev_get_plat(bus); + void __iomem *base = plat->base; u32 mbrdiv; long div; @@ -353,7 +373,7 @@ static int stm32_spi_set_speed(struct udevice *bus, uint hz) if (!mbrdiv) return -EINVAL; - clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_MBR, + clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_MBR, (mbrdiv - 1) << SPI_CFG1_MBR_SHIFT); priv->cur_hz = hz; @@ -367,6 +387,8 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, struct udevice *bus = dev_get_parent(slave); struct dm_spi_slave_plat *slave_plat; struct stm32_spi_priv *priv = dev_get_priv(bus); + struct stm32_spi_plat *plat = dev_get_plat(bus); + void __iomem *base = plat->base; u32 sr; u32 ifcr = 0; u32 xferlen; @@ -376,7 +398,7 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, xferlen = bitlen / 8; if (xferlen <= SPI_CR2_TSIZE) - writel(xferlen, priv->base + STM32_SPI_CR2); + writel(xferlen, base + STM32_SPI_CR2); else return -EMSGSIZE; @@ -396,15 +418,15 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, priv->cur_xferlen = xferlen; /* Disable the SPI hardware to unlock CFG1/CFG2 registers */ - stm32_spi_disable(priv); + stm32_spi_disable(base); - clrsetbits_le32(priv->base + STM32_SPI_CFG2, SPI_CFG2_COMM, + clrsetbits_le32(base + STM32_SPI_CFG2, SPI_CFG2_COMM, mode << SPI_CFG2_COMM_SHIFT); stm32_spi_set_fthlv(bus, xferlen); /* Enable the SPI hardware */ - stm32_spi_enable(priv); + stm32_spi_enable(base); } dev_dbg(bus, "priv->tx_len=%d priv->rx_len=%d\n", @@ -416,12 +438,12 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, /* Be sure to have data in fifo before starting data transfer */ if (priv->tx_buf) - stm32_spi_write_txfifo(priv); + stm32_spi_write_txfifo(bus); - setbits_le32(priv->base + STM32_SPI_CR1, SPI_CR1_CSTART); + setbits_le32(base + STM32_SPI_CR1, SPI_CR1_CSTART); while (1) { - sr = readl(priv->base + STM32_SPI_SR); + sr = readl(base + STM32_SPI_SR); if (sr & SPI_SR_OVR) { dev_err(bus, "Overrun: RX data lost\n"); @@ -433,7 +455,7 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, dev_warn(bus, "System too slow is limiting data throughput\n"); if (priv->rx_buf && priv->rx_len > 0) - stm32_spi_read_rxfifo(priv); + stm32_spi_read_rxfifo(bus); ifcr |= SPI_SR_SUSP; } @@ -443,23 +465,23 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, if (sr & SPI_SR_TXP) if (priv->tx_buf && priv->tx_len > 0) - stm32_spi_write_txfifo(priv); + stm32_spi_write_txfifo(bus); if (sr & SPI_SR_RXP) if (priv->rx_buf && priv->rx_len > 0) - stm32_spi_read_rxfifo(priv); + stm32_spi_read_rxfifo(bus); if (sr & SPI_SR_EOT) { if (priv->rx_buf && priv->rx_len > 0) - stm32_spi_read_rxfifo(priv); + stm32_spi_read_rxfifo(bus); break; } - writel(ifcr, priv->base + STM32_SPI_IFCR); + writel(ifcr, base + STM32_SPI_IFCR); } /* clear status flags */ - setbits_le32(priv->base + STM32_SPI_IFCR, SPI_IFCR_ALL); + setbits_le32(base + STM32_SPI_IFCR, SPI_IFCR_ALL); stm32_spi_stopxfer(bus); if (flags & SPI_XFER_END) @@ -470,42 +492,72 @@ static int stm32_spi_xfer(struct udevice *slave, unsigned int bitlen, static int stm32_spi_get_fifo_size(struct udevice *dev) { - struct stm32_spi_priv *priv = dev_get_priv(dev); + struct stm32_spi_plat *plat = dev_get_plat(dev); + void __iomem *base = plat->base; u32 count = 0; - stm32_spi_enable(priv); + stm32_spi_enable(base); - while (readl(priv->base + STM32_SPI_SR) & SPI_SR_TXP) - writeb(++count, priv->base + STM32_SPI_TXDR); + while (readl(base + STM32_SPI_SR) & SPI_SR_TXP) + writeb(++count, base + STM32_SPI_TXDR); - stm32_spi_disable(priv); + stm32_spi_disable(base); dev_dbg(dev, "%d x 8-bit fifo size\n", count); return count; } +static int stm32_spi_of_to_plat(struct udevice *dev) +{ + struct stm32_spi_plat *plat = dev_get_plat(dev); + int ret; + + plat->base = dev_read_addr_ptr(dev); + if (!plat->base) { + dev_err(dev, "can't get registers base address\n"); + return -ENOENT; + } + + ret = clk_get_by_index(dev, 0, &plat->clk); + if (ret < 0) + return ret; + + ret = reset_get_by_index(dev, 0, &plat->rst_ctl); + if (ret < 0) + goto clk_err; + + ret = gpio_request_list_by_name(dev, "cs-gpios", plat->cs_gpios, + ARRAY_SIZE(plat->cs_gpios), 0); + if (ret < 0) { + dev_err(dev, "Can't get %s cs gpios: %d", dev->name, ret); + ret = -ENOENT; + goto clk_err; + } + + return 0; + +clk_err: + clk_free(&plat->clk); + + return ret; +} + static int stm32_spi_probe(struct udevice *dev) { + struct stm32_spi_plat *plat = dev_get_plat(dev); struct stm32_spi_priv *priv = dev_get_priv(dev); + void __iomem *base = plat->base; unsigned long clk_rate; int ret; unsigned int i; - priv->base = dev_remap_addr(dev); - if (!priv->base) - return -EINVAL; - /* enable clock */ - ret = clk_get_by_index(dev, 0, &priv->clk); + ret = clk_enable(&plat->clk); if (ret < 0) return ret; - ret = clk_enable(&priv->clk); - if (ret < 0) - return ret; - - clk_rate = clk_get_rate(&priv->clk); + clk_rate = clk_get_rate(&plat->clk); if (!clk_rate) { ret = -EINVAL; goto clk_err; @@ -514,46 +566,34 @@ static int stm32_spi_probe(struct udevice *dev) priv->bus_clk_rate = clk_rate; /* perform reset */ - ret = reset_get_by_index(dev, 0, &priv->rst_ctl); - if (ret < 0) - goto clk_err; - - reset_assert(&priv->rst_ctl); + reset_assert(&plat->rst_ctl); udelay(2); - reset_deassert(&priv->rst_ctl); - - ret = gpio_request_list_by_name(dev, "cs-gpios", priv->cs_gpios, - ARRAY_SIZE(priv->cs_gpios), 0); - if (ret < 0) { - dev_err(dev, "Can't get cs gpios: %d", ret); - goto reset_err; - } + reset_deassert(&plat->rst_ctl); priv->fifo_size = stm32_spi_get_fifo_size(dev); - priv->cur_mode = SPI_FULL_DUPLEX; priv->cur_xferlen = 0; priv->cur_bpw = SPI_DEFAULT_WORDLEN; - clrsetbits_le32(priv->base + STM32_SPI_CFG1, SPI_CFG1_DSIZE, + clrsetbits_le32(base + STM32_SPI_CFG1, SPI_CFG1_DSIZE, priv->cur_bpw - 1); - for (i = 0; i < ARRAY_SIZE(priv->cs_gpios); i++) { - if (!dm_gpio_is_valid(&priv->cs_gpios[i])) + for (i = 0; i < ARRAY_SIZE(plat->cs_gpios); i++) { + if (!dm_gpio_is_valid(&plat->cs_gpios[i])) continue; - dm_gpio_set_dir_flags(&priv->cs_gpios[i], + dm_gpio_set_dir_flags(&plat->cs_gpios[i], GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE); } /* Ensure I2SMOD bit is kept cleared */ - clrbits_le32(priv->base + STM32_SPI_I2SCFGR, SPI_I2SCFGR_I2SMOD); + clrbits_le32(base + STM32_SPI_I2SCFGR, SPI_I2SCFGR_I2SMOD); /* * - SS input value high * - transmitter half duplex direction * - automatic communication suspend when RX-Fifo is full */ - setbits_le32(priv->base + STM32_SPI_CR1, + setbits_le32(base + STM32_SPI_CR1, SPI_CR1_SSI | SPI_CR1_HDDIR | SPI_CR1_MASRX); /* @@ -562,40 +602,38 @@ static int stm32_spi_probe(struct udevice *dev) * SS input value is determined by the SSI bit * - keep control of all associated GPIOs */ - setbits_le32(priv->base + STM32_SPI_CFG2, + setbits_le32(base + STM32_SPI_CFG2, SPI_CFG2_MASTER | SPI_CFG2_SSM | SPI_CFG2_AFCNTR); return 0; -reset_err: - reset_free(&priv->rst_ctl); - clk_err: - clk_disable(&priv->clk); - clk_free(&priv->clk); + clk_disable(&plat->clk); + clk_free(&plat->clk); return ret; }; static int stm32_spi_remove(struct udevice *dev) { - struct stm32_spi_priv *priv = dev_get_priv(dev); + struct stm32_spi_plat *plat = dev_get_plat(dev); + void __iomem *base = plat->base; int ret; stm32_spi_stopxfer(dev); - stm32_spi_disable(priv); + stm32_spi_disable(base); - ret = reset_assert(&priv->rst_ctl); + ret = reset_assert(&plat->rst_ctl); if (ret < 0) return ret; - reset_free(&priv->rst_ctl); + reset_free(&plat->rst_ctl); - ret = clk_disable(&priv->clk); + ret = clk_disable(&plat->clk); if (ret < 0) return ret; - clk_free(&priv->clk); + clk_free(&plat->clk); return ret; }; @@ -618,7 +656,9 @@ U_BOOT_DRIVER(stm32_spi) = { .id = UCLASS_SPI, .of_match = stm32_spi_ids, .ops = &stm32_spi_ops, - .priv_auto = sizeof(struct stm32_spi_priv), + .of_to_plat = stm32_spi_of_to_plat, + .plat_auto = sizeof(struct stm32_spi_plat), + .priv_auto = sizeof(struct stm32_spi_priv), .probe = stm32_spi_probe, .remove = stm32_spi_remove, }; diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index ac77ffbc8be..43a948cfcde 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -85,6 +85,18 @@ config SYSRESET_PSCI Enable PSCI SYSTEM_RESET function call. To use this, PSCI firmware must be running on your system. +config SYSRESET_SBI + bool "Enable support for SBI System Reset" + depends on RISCV_SMODE && SBI_V02 + select SYSRESET_CMD_POWEROFF if CMD_POWEROFF + help + Enable system reset and poweroff via the SBI system reset extension. + The extension was introduced in version 0.3 of the SBI specification. + + If the SBI implementation provides the extension, is board specific. + The RISC-V platform specification mandates the extension for rich + operating system platforms. + config SYSRESET_SOCFPGA bool "Enable support for Intel SOCFPGA family" depends on ARCH_SOCFPGA && (TARGET_SOCFPGA_GEN5 || TARGET_SOCFPGA_ARRIA10) diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index de81c399d79..8e00be07794 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_SYSRESET_MPC83XX) += sysreset_mpc83xx.o obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o obj-$(CONFIG_SYSRESET_OCTEON) += sysreset_octeon.o obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o +obj-$(CONFIG_SYSRESET_SBI) += sysreset_sbi.o obj-$(CONFIG_SYSRESET_SOCFPGA) += sysreset_socfpga.o obj-$(CONFIG_SYSRESET_SOCFPGA_SOC64) += sysreset_socfpga_soc64.o obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o diff --git a/drivers/sysreset/sysreset_sbi.c b/drivers/sysreset/sysreset_sbi.c new file mode 100644 index 00000000000..5e8090d62bf --- /dev/null +++ b/drivers/sysreset/sysreset_sbi.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2021, Heinrich Schuchardt <heinrich.schuchardt@canonical.com> + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <log.h> +#include <sysreset.h> +#include <asm/sbi.h> + +static enum sbi_srst_reset_type reset_type_map[SYSRESET_COUNT] = { + [SYSRESET_WARM] = SBI_SRST_RESET_TYPE_WARM_REBOOT, + [SYSRESET_COLD] = SBI_SRST_RESET_TYPE_COLD_REBOOT, + [SYSRESET_POWER] = SBI_SRST_RESET_TYPE_COLD_REBOOT, + [SYSRESET_POWER_OFF] = SBI_SRST_RESET_TYPE_SHUTDOWN, +}; + +static int sbi_sysreset_request(struct udevice *dev, enum sysreset_t type) +{ + enum sbi_srst_reset_type reset_type; + + reset_type = reset_type_map[type]; + sbi_srst_reset(reset_type, SBI_SRST_RESET_REASON_NONE); + + return -EINPROGRESS; +} + +static int sbi_sysreset_probe(struct udevice *dev) +{ + long have_reset; + + have_reset = sbi_probe_extension(SBI_EXT_SRST); + if (have_reset) + return 0; + + log_warning("SBI has no system reset extension\n"); + return -ENOENT; +} + +static struct sysreset_ops sbi_sysreset_ops = { + .request = sbi_sysreset_request, +}; + +U_BOOT_DRIVER(sbi_sysreset) = { + .name = "sbi-sysreset", + .id = UCLASS_SYSRESET, + .ops = &sbi_sysreset_ops, + .probe = sbi_sysreset_probe, +}; diff --git a/drivers/timer/timer-uclass.c b/drivers/timer/timer-uclass.c index 6ea9e39e126..cbc36476987 100644 --- a/drivers/timer/timer-uclass.c +++ b/drivers/timer/timer-uclass.c @@ -148,7 +148,7 @@ int notrace dm_timer_init(void) * If the timer is not marked to be bound before * relocation, bind it anyway. */ - if (!lists_bind_fdt(dm_root(), node, &dev, false)) { + if (!lists_bind_fdt(dm_root(), node, &dev, NULL, false)) { ret = device_probe(dev); if (ret) return ret; diff --git a/drivers/usb/dwc3/dwc3-meson-gxl.c b/drivers/usb/dwc3/dwc3-meson-gxl.c index 7c26290c15c..6c6d463203c 100644 --- a/drivers/usb/dwc3/dwc3-meson-gxl.c +++ b/drivers/usb/dwc3/dwc3-meson-gxl.c @@ -409,6 +409,7 @@ static int dwc3_meson_gxl_remove(struct udevice *dev) } static const struct udevice_id dwc3_meson_gxl_ids[] = { + { .compatible = "amlogic,meson-axg-usb-ctrl" }, { .compatible = "amlogic,meson-gxl-usb-ctrl" }, { .compatible = "amlogic,meson-gxm-usb-ctrl" }, { } diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index 0cdf47c2dda..06e6a489495 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -167,6 +167,12 @@ #define gadget_is_mtu3(g) 0 #endif +#ifdef CONFIG_USB_GADGET_DWC2_OTG +#define gadget_is_dwc2(g) (!strcmp("dwc2-udc", (g)->name)) +#else +#define gadget_is_dwc2(g) 0 +#endif + /** * usb_gadget_controller_number - support bcdDevice id convention * @gadget: the controller being driven @@ -232,5 +238,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x25; else if (gadget_is_mtu3(gadget)) return 0x26; + else if (gadget_is_dwc2(gadget)) + return 0x27; return -ENOENT; } diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 10b0479a8a6..ccecb5a3b08 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -139,6 +139,9 @@ config USB_EHCI_HCD if USB_EHCI_HCD +config USB_EHCI_IS_TDI + bool + config USB_EHCI_ATMEL bool "Support for Atmel on-chip EHCI USB controller" depends on ARCH_AT91 @@ -150,6 +153,7 @@ config USB_EHCI_MARVELL bool "Support for Marvell on-chip EHCI USB controller" depends on ARCH_MVEBU || ARCH_KIRKWOOD || ARCH_ORION5X default y + select USB_EHCI_IS_TDI if !ARM64 ---help--- Enables support for the on-chip EHCI controller on MVEBU SoCs. @@ -175,6 +179,14 @@ config USB_EHCI_MX7 ---help--- Enables support for the on-chip EHCI controller on i.MX7 SoCs. +config USB_EHCI_MXS + bool "Support for i.MX23 EHCI USB controller" + depends on ARCH_MX23 + default y + select USB_EHCI_IS_TDI + help + Enables support for the on-chip EHCI controller on i.MX23 SoCs. + config USB_EHCI_OMAP bool "Support for OMAP3+ on-chip EHCI USB controller" depends on ARCH_OMAP2PLUS @@ -251,12 +263,14 @@ config USB_EHCI_PCI config USB_EHCI_TEGRA bool "Support for NVIDIA Tegra on-chip EHCI USB controller" depends on ARCH_TEGRA + select USB_EHCI_IS_TDI ---help--- Enable support for Tegra on-chip EHCI USB controller config USB_EHCI_ZYNQ bool "Support for Xilinx Zynq on-chip EHCI USB controller" default y if ARCH_ZYNQ + select USB_EHCI_IS_TDI ---help--- Enable support for Zynq on-chip EHCI USB controller diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index ba75c27d04e..e6355263cb9 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -108,7 +108,7 @@ static struct descriptor { }, }; -#if defined(CONFIG_EHCI_IS_TDI) +#if defined(CONFIG_USB_EHCI_IS_TDI) #define ehci_is_TDI() (1) #else #define ehci_is_TDI() (0) diff --git a/drivers/usb/host/usb-sandbox.c b/drivers/usb/host/usb-sandbox.c index d7cc92aa544..d1103dcb2e9 100644 --- a/drivers/usb/host/usb-sandbox.c +++ b/drivers/usb/host/usb-sandbox.c @@ -9,6 +9,13 @@ #include <log.h> #include <usb.h> #include <dm/root.h> +#include <linux/usb/gadget.h> + +struct sandbox_udc { + struct usb_gadget gadget; +}; + +struct sandbox_udc *this_controller; struct sandbox_usb_ctrl { int rootdev; @@ -117,6 +124,27 @@ static int sandbox_submit_int(struct udevice *bus, struct usb_device *udev, return ret; } +int usb_gadget_handle_interrupts(int index) +{ + return 0; +} + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct sandbox_udc *dev = this_controller; + + return driver->bind(&dev->gadget); +} + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct sandbox_udc *dev = this_controller; + + driver->unbind(&dev->gadget); + + return 0; +} + static int sandbox_alloc_device(struct udevice *dev, struct usb_device *udev) { struct sandbox_usb_ctrl *ctrl = dev_get_priv(dev); diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c index fea4105f3d1..7e62e3fe6ea 100644 --- a/drivers/usb/musb-new/sunxi.c +++ b/drivers/usb/musb-new/sunxi.c @@ -25,8 +25,6 @@ #include <reset.h> #include <asm/arch/cpu.h> #include <asm/arch/clock.h> -#include <asm/arch/gpio.h> -#include <asm-generic/gpio.h> #include <dm/device_compat.h> #include <dm/lists.h> #include <dm/root.h> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index b1f8a9c1e62..2f4650f8309 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -452,7 +452,7 @@ config VIDEO_LCD_SSD2828_RESET default "" ---help--- The reset pin of SSD2828 chip. This takes a string in the format - understood by 'name_to_gpio' function, e.g. PH1 for pin 1 of port H. + understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. config VIDEO_LCD_TDO_TL070WSH30 bool "TDO TL070WSH30 DSI LCD panel support" @@ -477,7 +477,7 @@ config VIDEO_LCD_SPI_CS This is one of the SPI communication pins, involved in setting up a working LCD configuration. The exact role of SPI may differ for different hardware setups. The option takes a string in the format - understood by 'name_to_gpio' function, e.g. PH1 for pin 1 of port H. + understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. config VIDEO_LCD_SPI_SCLK string "SPI SCLK pin for LCD related config job" @@ -487,7 +487,7 @@ config VIDEO_LCD_SPI_SCLK This is one of the SPI communication pins, involved in setting up a working LCD configuration. The exact role of SPI may differ for different hardware setups. The option takes a string in the format - understood by 'name_to_gpio' function, e.g. PH1 for pin 1 of port H. + understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. config VIDEO_LCD_SPI_MOSI string "SPI MOSI pin for LCD related config job" @@ -497,7 +497,7 @@ config VIDEO_LCD_SPI_MOSI This is one of the SPI communication pins, involved in setting up a working LCD configuration. The exact role of SPI may differ for different hardware setups. The option takes a string in the format - understood by 'name_to_gpio' function, e.g. PH1 for pin 1 of port H. + understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. config VIDEO_LCD_SPI_MISO string "SPI MISO pin for LCD related config job (optional)" @@ -509,7 +509,7 @@ config VIDEO_LCD_SPI_MISO different hardware setups. If wired up, this pin may provide additional useful functionality. Such as bi-directional communication with the hardware and LCD panel id retrieval (if the panel can report it). The - option takes a string in the format understood by 'name_to_gpio' + option takes a string in the format understood by 'sunxi_name_to_gpio' function, e.g. PH1 for pin 1 of port H. source "drivers/video/meson/Kconfig" @@ -648,6 +648,12 @@ source "drivers/video/bridge/Kconfig" source "drivers/video/imx/Kconfig" +config VIDEO_MXS + bool "Enable video support on i.MX28/i.MX6UL/i.MX7 SoCs" + depends on DM_VIDEO + help + Enable framebuffer driver for i.MX28/i.MX6UL/i.MX7 processors + config VIDEO_NX bool "Enable video support on Nexell SoC" depends on ARCH_S5P6818 || ARCH_S5P4418 diff --git a/drivers/video/Makefile b/drivers/video/Makefile index f6d07b343f0..8956b5f9b00 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -61,7 +61,6 @@ obj-$(CONFIG_VIDEO_MCDE_SIMPLE) += mcde_simple.o obj-${CONFIG_VIDEO_MESON} += meson/ obj-${CONFIG_VIDEO_MIPI_DSI} += mipi_dsi.o obj-$(CONFIG_VIDEO_MVEBU) += mvebu_lcd.o -obj-$(CONFIG_VIDEO_MX3) += mx3fb.o videomodes.o obj-$(CONFIG_VIDEO_MXS) += mxsfb.o videomodes.o obj-$(CONFIG_VIDEO_NX) += nexell_display.o videomodes.o nexell/ obj-$(CONFIG_VIDEO_OMAP3) += omap3_dss.o diff --git a/drivers/video/anx9804.c b/drivers/video/anx9804.c index 3037ff39b41..52b5988ba5f 100644 --- a/drivers/video/anx9804.c +++ b/drivers/video/anx9804.c @@ -21,18 +21,23 @@ * This function will init an anx9804 parallel lcd to dp bridge chip * using the passed in parameters. * - * @i2c_bus: Number of the i2c bus to which the anx9804 is connected. + * @i2c_bus: Device of the i2c bus to which the anx9804 is connected. * @lanes: Number of displayport lanes to use * @data_rate: Register value for the bandwidth reg 0x06: 1.62G, 0x0a: 2.7G * @bpp: Bits per pixel, must be 18 or 24 */ -void anx9804_init(unsigned int i2c_bus, u8 lanes, u8 data_rate, int bpp) +void anx9804_init(struct udevice *i2c_bus, u8 lanes, u8 data_rate, int bpp) { - unsigned int orig_i2c_bus = i2c_get_bus_num(); - u8 c, colordepth; - int i; + struct udevice *chip0, *chip1; + int c, colordepth, i, ret; - i2c_set_bus_num(i2c_bus); + ret = i2c_get_chip(i2c_bus, 0x38, 1, &chip0); + if (ret) + return; + + ret = i2c_get_chip(i2c_bus, 0x39, 1, &chip1); + if (ret) + return; if (bpp == 18) colordepth = 0x00; /* 6 bit */ @@ -40,24 +45,23 @@ void anx9804_init(unsigned int i2c_bus, u8 lanes, u8 data_rate, int bpp) colordepth = 0x10; /* 8 bit */ /* Reset */ - i2c_reg_write(0x39, ANX9804_RST_CTRL_REG, 1); + dm_i2c_reg_write(chip1, ANX9804_RST_CTRL_REG, 1); mdelay(100); - i2c_reg_write(0x39, ANX9804_RST_CTRL_REG, 0); + dm_i2c_reg_write(chip1, ANX9804_RST_CTRL_REG, 0); /* Write 0 to the powerdown reg (powerup everything) */ - i2c_reg_write(0x39, ANX9804_POWERD_CTRL_REG, 0); + dm_i2c_reg_write(chip1, ANX9804_POWERD_CTRL_REG, 0); - c = i2c_reg_read(0x39, ANX9804_DEV_IDH_REG); + c = dm_i2c_reg_read(chip1, ANX9804_DEV_IDH_REG); if (c != 0x98) { printf("Error anx9804 chipid mismatch\n"); - i2c_set_bus_num(orig_i2c_bus); return; } for (i = 0; i < 100; i++) { - c = i2c_reg_read(0x38, ANX9804_SYS_CTRL2_REG); - i2c_reg_write(0x38, ANX9804_SYS_CTRL2_REG, c); - c = i2c_reg_read(0x38, ANX9804_SYS_CTRL2_REG); + c = dm_i2c_reg_read(chip0, ANX9804_SYS_CTRL2_REG); + dm_i2c_reg_write(chip0, ANX9804_SYS_CTRL2_REG, c); + c = dm_i2c_reg_read(chip0, ANX9804_SYS_CTRL2_REG); if ((c & ANX9804_SYS_CTRL2_CHA_STA) == 0) break; @@ -66,51 +70,51 @@ void anx9804_init(unsigned int i2c_bus, u8 lanes, u8 data_rate, int bpp) if (i == 100) printf("Error anx9804 clock is not stable\n"); - i2c_reg_write(0x39, ANX9804_VID_CTRL2_REG, colordepth); + dm_i2c_reg_write(chip1, ANX9804_VID_CTRL2_REG, colordepth); /* Set a bunch of analog related register values */ - i2c_reg_write(0x38, ANX9804_PLL_CTRL_REG, 0x07); - i2c_reg_write(0x39, ANX9804_PLL_FILTER_CTRL3, 0x19); - i2c_reg_write(0x39, ANX9804_PLL_CTRL3, 0xd9); - i2c_reg_write(0x39, ANX9804_RST_CTRL2_REG, ANX9804_RST_CTRL2_AC_MODE); - i2c_reg_write(0x39, ANX9804_ANALOG_DEBUG_REG1, 0xf0); - i2c_reg_write(0x39, ANX9804_ANALOG_DEBUG_REG3, 0x99); - i2c_reg_write(0x39, ANX9804_PLL_FILTER_CTRL1, 0x7b); - i2c_reg_write(0x38, ANX9804_LINK_DEBUG_REG, 0x30); - i2c_reg_write(0x39, ANX9804_PLL_FILTER_CTRL, 0x06); + dm_i2c_reg_write(chip0, ANX9804_PLL_CTRL_REG, 0x07); + dm_i2c_reg_write(chip1, ANX9804_PLL_FILTER_CTRL3, 0x19); + dm_i2c_reg_write(chip1, ANX9804_PLL_CTRL3, 0xd9); + dm_i2c_reg_write(chip1, ANX9804_RST_CTRL2_REG, ANX9804_RST_CTRL2_AC_MODE); + dm_i2c_reg_write(chip1, ANX9804_ANALOG_DEBUG_REG1, 0xf0); + dm_i2c_reg_write(chip1, ANX9804_ANALOG_DEBUG_REG3, 0x99); + dm_i2c_reg_write(chip1, ANX9804_PLL_FILTER_CTRL1, 0x7b); + dm_i2c_reg_write(chip0, ANX9804_LINK_DEBUG_REG, 0x30); + dm_i2c_reg_write(chip1, ANX9804_PLL_FILTER_CTRL, 0x06); /* Force HPD */ - i2c_reg_write(0x38, ANX9804_SYS_CTRL3_REG, - ANX9804_SYS_CTRL3_F_HPD | ANX9804_SYS_CTRL3_HPD_CTRL); + dm_i2c_reg_write(chip0, ANX9804_SYS_CTRL3_REG, + ANX9804_SYS_CTRL3_F_HPD | ANX9804_SYS_CTRL3_HPD_CTRL); /* Power up and configure lanes */ - i2c_reg_write(0x38, ANX9804_ANALOG_POWER_DOWN_REG, 0x00); - i2c_reg_write(0x38, ANX9804_TRAINING_LANE0_SET_REG, 0x00); - i2c_reg_write(0x38, ANX9804_TRAINING_LANE1_SET_REG, 0x00); - i2c_reg_write(0x38, ANX9804_TRAINING_LANE2_SET_REG, 0x00); - i2c_reg_write(0x38, ANX9804_TRAINING_LANE3_SET_REG, 0x00); + dm_i2c_reg_write(chip0, ANX9804_ANALOG_POWER_DOWN_REG, 0x00); + dm_i2c_reg_write(chip0, ANX9804_TRAINING_LANE0_SET_REG, 0x00); + dm_i2c_reg_write(chip0, ANX9804_TRAINING_LANE1_SET_REG, 0x00); + dm_i2c_reg_write(chip0, ANX9804_TRAINING_LANE2_SET_REG, 0x00); + dm_i2c_reg_write(chip0, ANX9804_TRAINING_LANE3_SET_REG, 0x00); /* Reset AUX CH */ - i2c_reg_write(0x39, ANX9804_RST_CTRL2_REG, - ANX9804_RST_CTRL2_AC_MODE | ANX9804_RST_CTRL2_AUX); - i2c_reg_write(0x39, ANX9804_RST_CTRL2_REG, - ANX9804_RST_CTRL2_AC_MODE); + dm_i2c_reg_write(chip1, ANX9804_RST_CTRL2_REG, + ANX9804_RST_CTRL2_AC_MODE | ANX9804_RST_CTRL2_AUX); + dm_i2c_reg_write(chip1, ANX9804_RST_CTRL2_REG, + ANX9804_RST_CTRL2_AC_MODE); /* Powerdown audio and some other unused bits */ - i2c_reg_write(0x39, ANX9804_POWERD_CTRL_REG, ANX9804_POWERD_AUDIO); - i2c_reg_write(0x38, ANX9804_HDCP_CONTROL_0_REG, 0x00); - i2c_reg_write(0x38, 0xa7, 0x00); + dm_i2c_reg_write(chip1, ANX9804_POWERD_CTRL_REG, ANX9804_POWERD_AUDIO); + dm_i2c_reg_write(chip0, ANX9804_HDCP_CONTROL_0_REG, 0x00); + dm_i2c_reg_write(chip0, 0xa7, 0x00); /* Set data-rate / lanes */ - i2c_reg_write(0x38, ANX9804_LINK_BW_SET_REG, data_rate); - i2c_reg_write(0x38, ANX9804_LANE_COUNT_SET_REG, lanes); + dm_i2c_reg_write(chip0, ANX9804_LINK_BW_SET_REG, data_rate); + dm_i2c_reg_write(chip0, ANX9804_LANE_COUNT_SET_REG, lanes); /* Link training */ - i2c_reg_write(0x38, ANX9804_LINK_TRAINING_CTRL_REG, - ANX9804_LINK_TRAINING_CTRL_EN); + dm_i2c_reg_write(chip0, ANX9804_LINK_TRAINING_CTRL_REG, + ANX9804_LINK_TRAINING_CTRL_EN); mdelay(5); for (i = 0; i < 100; i++) { - c = i2c_reg_read(0x38, ANX9804_LINK_TRAINING_CTRL_REG); + c = dm_i2c_reg_read(chip0, ANX9804_LINK_TRAINING_CTRL_REG); if ((c & 0x01) == 0) break; @@ -118,17 +122,14 @@ void anx9804_init(unsigned int i2c_bus, u8 lanes, u8 data_rate, int bpp) } if(i == 100) { printf("Error anx9804 link training timeout\n"); - i2c_set_bus_num(orig_i2c_bus); return; } /* Enable */ - i2c_reg_write(0x39, ANX9804_VID_CTRL1_REG, - ANX9804_VID_CTRL1_VID_EN | ANX9804_VID_CTRL1_EDGE); + dm_i2c_reg_write(chip1, ANX9804_VID_CTRL1_REG, + ANX9804_VID_CTRL1_VID_EN | ANX9804_VID_CTRL1_EDGE); /* Force stream valid */ - i2c_reg_write(0x38, ANX9804_SYS_CTRL3_REG, - ANX9804_SYS_CTRL3_F_HPD | ANX9804_SYS_CTRL3_HPD_CTRL | - ANX9804_SYS_CTRL3_F_VALID | ANX9804_SYS_CTRL3_VALID_CTRL); - - i2c_set_bus_num(orig_i2c_bus); + dm_i2c_reg_write(chip0, ANX9804_SYS_CTRL3_REG, + ANX9804_SYS_CTRL3_F_HPD | ANX9804_SYS_CTRL3_HPD_CTRL | + ANX9804_SYS_CTRL3_F_VALID | ANX9804_SYS_CTRL3_VALID_CTRL); } diff --git a/drivers/video/anx9804.h b/drivers/video/anx9804.h index c0fe3b393b4..ea6c9f2d558 100644 --- a/drivers/video/anx9804.h +++ b/drivers/video/anx9804.h @@ -16,9 +16,10 @@ #define ANX9804_DATA_RATE_2700M 0x0a #ifdef CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804 -void anx9804_init(unsigned int i2c_bus, u8 lanes, u8 data_rate, int bpp); +void anx9804_init(struct udevice *i2c_bus, u8 lanes, u8 data_rate, int bpp); #else -static inline void anx9804_init(unsigned int i2c_bus, u8 lanes, u8 data_rate, +static inline void anx9804_init(struct udevice *i2c_bus, u8 lanes, u8 data_rate, int bpp) {} #endif + #endif diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index 566fc1e01a4..7df7d57e6ec 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -78,17 +78,6 @@ #include <dm/ofnode.h> #include <linux/compiler.h> -#if defined(CONFIG_VIDEO_MXS) -#define VIDEO_FB_16BPP_WORD_SWAP -#endif - -/* - * Defines for the i.MX31 driver (mx3fb.c) - */ -#if defined(CONFIG_VIDEO_MX3) || defined(CONFIG_VIDEO_IPUV3) -#define VIDEO_FB_16BPP_WORD_SWAP -#endif - /* * Include video_fb.h after definitions of VIDEO_HW_RECTFILL etc. */ diff --git a/drivers/video/hitachi_tx18d42vm_lcd.c b/drivers/video/hitachi_tx18d42vm_lcd.c index c6c8df6a96e..87c4d27438a 100644 --- a/drivers/video/hitachi_tx18d42vm_lcd.c +++ b/drivers/video/hitachi_tx18d42vm_lcd.c @@ -49,9 +49,9 @@ int hitachi_tx18d42vm_init(void) }; int i, cs, clk, mosi, ret = 0; - cs = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS); - clk = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK); - mosi = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI); + cs = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS); + clk = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK); + mosi = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI); if (cs == -1 || clk == -1 || mosi == 1) { printf("Error tx18d42vm spi gpio config is invalid\n"); diff --git a/drivers/video/mx3fb.c b/drivers/video/mx3fb.c deleted file mode 100644 index e6dd2b83c6f..00000000000 --- a/drivers/video/mx3fb.c +++ /dev/null @@ -1,906 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Copyright (C) 2009 - * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de> - * Copyright (C) 2011 - * HALE electronic GmbH, <helmut.raiger@hale.at> - */ -#include <common.h> -#include <env.h> -#include <log.h> -#include <malloc.h> -#include <video_fb.h> -#include <linux/delay.h> - -#include <asm/arch/imx-regs.h> -#include <asm/arch/clock.h> -#include <linux/errno.h> -#include <asm/io.h> - -#include "videomodes.h" - -/* this might need panel specific set-up as-well */ -#define IF_CONF 0 - -/* -------------- controller specific stuff -------------- */ - -/* IPU DMA Controller channel definitions. */ -enum ipu_channel { - IDMAC_IC_0 = 0, /* IC (encoding task) to memory */ - IDMAC_IC_1 = 1, /* IC (viewfinder task) to memory */ - IDMAC_ADC_0 = 1, - IDMAC_IC_2 = 2, - IDMAC_ADC_1 = 2, - IDMAC_IC_3 = 3, - IDMAC_IC_4 = 4, - IDMAC_IC_5 = 5, - IDMAC_IC_6 = 6, - IDMAC_IC_7 = 7, /* IC (sensor data) to memory */ - IDMAC_IC_8 = 8, - IDMAC_IC_9 = 9, - IDMAC_IC_10 = 10, - IDMAC_IC_11 = 11, - IDMAC_IC_12 = 12, - IDMAC_IC_13 = 13, - IDMAC_SDC_0 = 14, /* Background synchronous display data */ - IDMAC_SDC_1 = 15, /* Foreground data (overlay) */ - IDMAC_SDC_2 = 16, - IDMAC_SDC_3 = 17, - IDMAC_ADC_2 = 18, - IDMAC_ADC_3 = 19, - IDMAC_ADC_4 = 20, - IDMAC_ADC_5 = 21, - IDMAC_ADC_6 = 22, - IDMAC_ADC_7 = 23, - IDMAC_PF_0 = 24, - IDMAC_PF_1 = 25, - IDMAC_PF_2 = 26, - IDMAC_PF_3 = 27, - IDMAC_PF_4 = 28, - IDMAC_PF_5 = 29, - IDMAC_PF_6 = 30, - IDMAC_PF_7 = 31, -}; - -/* More formats can be copied from the Linux driver if needed */ -enum pixel_fmt { - /* 2 bytes */ - IPU_PIX_FMT_RGB565, - IPU_PIX_FMT_RGB666, - IPU_PIX_FMT_BGR666, - /* 3 bytes */ - IPU_PIX_FMT_RGB24, -}; - -struct pixel_fmt_cfg { - u32 b0; - u32 b1; - u32 b2; - u32 acc; -}; - -static struct pixel_fmt_cfg fmt_cfg[] = { - [IPU_PIX_FMT_RGB24] = { - 0x1600AAAA, 0x00E05555, 0x00070000, 3, - }, - [IPU_PIX_FMT_RGB666] = { - 0x0005000F, 0x000B000F, 0x0011000F, 1, - }, - [IPU_PIX_FMT_BGR666] = { - 0x0011000F, 0x000B000F, 0x0005000F, 1, - }, - [IPU_PIX_FMT_RGB565] = { - 0x0004003F, 0x000A000F, 0x000F003F, 1, - } -}; - -enum ipu_panel { - IPU_PANEL_SHARP_TFT, - IPU_PANEL_TFT, -}; - -/* IPU Common registers */ -/* IPU_CONF and its bits already defined in imx-regs.h */ -#define IPU_CHA_BUF0_RDY (0x04 + IPU_BASE) -#define IPU_CHA_BUF1_RDY (0x08 + IPU_BASE) -#define IPU_CHA_DB_MODE_SEL (0x0C + IPU_BASE) -#define IPU_CHA_CUR_BUF (0x10 + IPU_BASE) -#define IPU_FS_PROC_FLOW (0x14 + IPU_BASE) -#define IPU_FS_DISP_FLOW (0x18 + IPU_BASE) -#define IPU_TASKS_STAT (0x1C + IPU_BASE) -#define IPU_IMA_ADDR (0x20 + IPU_BASE) -#define IPU_IMA_DATA (0x24 + IPU_BASE) -#define IPU_INT_CTRL_1 (0x28 + IPU_BASE) -#define IPU_INT_CTRL_2 (0x2C + IPU_BASE) -#define IPU_INT_CTRL_3 (0x30 + IPU_BASE) -#define IPU_INT_CTRL_4 (0x34 + IPU_BASE) -#define IPU_INT_CTRL_5 (0x38 + IPU_BASE) -#define IPU_INT_STAT_1 (0x3C + IPU_BASE) -#define IPU_INT_STAT_2 (0x40 + IPU_BASE) -#define IPU_INT_STAT_3 (0x44 + IPU_BASE) -#define IPU_INT_STAT_4 (0x48 + IPU_BASE) -#define IPU_INT_STAT_5 (0x4C + IPU_BASE) -#define IPU_BRK_CTRL_1 (0x50 + IPU_BASE) -#define IPU_BRK_CTRL_2 (0x54 + IPU_BASE) -#define IPU_BRK_STAT (0x58 + IPU_BASE) -#define IPU_DIAGB_CTRL (0x5C + IPU_BASE) - -/* Image Converter Registers */ -#define IC_CONF (0x88 + IPU_BASE) -#define IC_PRP_ENC_RSC (0x8C + IPU_BASE) -#define IC_PRP_VF_RSC (0x90 + IPU_BASE) -#define IC_PP_RSC (0x94 + IPU_BASE) -#define IC_CMBP_1 (0x98 + IPU_BASE) -#define IC_CMBP_2 (0x9C + IPU_BASE) -#define PF_CONF (0xA0 + IPU_BASE) -#define IDMAC_CONF (0xA4 + IPU_BASE) -#define IDMAC_CHA_EN (0xA8 + IPU_BASE) -#define IDMAC_CHA_PRI (0xAC + IPU_BASE) -#define IDMAC_CHA_BUSY (0xB0 + IPU_BASE) - -/* Image Converter Register bits */ -#define IC_CONF_PRPENC_EN 0x00000001 -#define IC_CONF_PRPENC_CSC1 0x00000002 -#define IC_CONF_PRPENC_ROT_EN 0x00000004 -#define IC_CONF_PRPVF_EN 0x00000100 -#define IC_CONF_PRPVF_CSC1 0x00000200 -#define IC_CONF_PRPVF_CSC2 0x00000400 -#define IC_CONF_PRPVF_CMB 0x00000800 -#define IC_CONF_PRPVF_ROT_EN 0x00001000 -#define IC_CONF_PP_EN 0x00010000 -#define IC_CONF_PP_CSC1 0x00020000 -#define IC_CONF_PP_CSC2 0x00040000 -#define IC_CONF_PP_CMB 0x00080000 -#define IC_CONF_PP_ROT_EN 0x00100000 -#define IC_CONF_IC_GLB_LOC_A 0x10000000 -#define IC_CONF_KEY_COLOR_EN 0x20000000 -#define IC_CONF_RWS_EN 0x40000000 -#define IC_CONF_CSI_MEM_WR_EN 0x80000000 - -/* SDC Registers */ -#define SDC_COM_CONF (0xB4 + IPU_BASE) -#define SDC_GW_CTRL (0xB8 + IPU_BASE) -#define SDC_FG_POS (0xBC + IPU_BASE) -#define SDC_BG_POS (0xC0 + IPU_BASE) -#define SDC_CUR_POS (0xC4 + IPU_BASE) -#define SDC_PWM_CTRL (0xC8 + IPU_BASE) -#define SDC_CUR_MAP (0xCC + IPU_BASE) -#define SDC_HOR_CONF (0xD0 + IPU_BASE) -#define SDC_VER_CONF (0xD4 + IPU_BASE) -#define SDC_SHARP_CONF_1 (0xD8 + IPU_BASE) -#define SDC_SHARP_CONF_2 (0xDC + IPU_BASE) - -/* Register bits */ -#define SDC_COM_TFT_COLOR 0x00000001UL -#define SDC_COM_FG_EN 0x00000010UL -#define SDC_COM_GWSEL 0x00000020UL -#define SDC_COM_GLB_A 0x00000040UL -#define SDC_COM_KEY_COLOR_G 0x00000080UL -#define SDC_COM_BG_EN 0x00000200UL -#define SDC_COM_SHARP 0x00001000UL - -#define SDC_V_SYNC_WIDTH_L 0x00000001UL - -/* Display Interface registers */ -#define DI_DISP_IF_CONF (0x0124 + IPU_BASE) -#define DI_DISP_SIG_POL (0x0128 + IPU_BASE) -#define DI_SER_DISP1_CONF (0x012C + IPU_BASE) -#define DI_SER_DISP2_CONF (0x0130 + IPU_BASE) -#define DI_HSP_CLK_PER (0x0134 + IPU_BASE) -#define DI_DISP0_TIME_CONF_1 (0x0138 + IPU_BASE) -#define DI_DISP0_TIME_CONF_2 (0x013C + IPU_BASE) -#define DI_DISP0_TIME_CONF_3 (0x0140 + IPU_BASE) -#define DI_DISP1_TIME_CONF_1 (0x0144 + IPU_BASE) -#define DI_DISP1_TIME_CONF_2 (0x0148 + IPU_BASE) -#define DI_DISP1_TIME_CONF_3 (0x014C + IPU_BASE) -#define DI_DISP2_TIME_CONF_1 (0x0150 + IPU_BASE) -#define DI_DISP2_TIME_CONF_2 (0x0154 + IPU_BASE) -#define DI_DISP2_TIME_CONF_3 (0x0158 + IPU_BASE) -#define DI_DISP3_TIME_CONF (0x015C + IPU_BASE) -#define DI_DISP0_DB0_MAP (0x0160 + IPU_BASE) -#define DI_DISP0_DB1_MAP (0x0164 + IPU_BASE) -#define DI_DISP0_DB2_MAP (0x0168 + IPU_BASE) -#define DI_DISP0_CB0_MAP (0x016C + IPU_BASE) -#define DI_DISP0_CB1_MAP (0x0170 + IPU_BASE) -#define DI_DISP0_CB2_MAP (0x0174 + IPU_BASE) -#define DI_DISP1_DB0_MAP (0x0178 + IPU_BASE) -#define DI_DISP1_DB1_MAP (0x017C + IPU_BASE) -#define DI_DISP1_DB2_MAP (0x0180 + IPU_BASE) -#define DI_DISP1_CB0_MAP (0x0184 + IPU_BASE) -#define DI_DISP1_CB1_MAP (0x0188 + IPU_BASE) -#define DI_DISP1_CB2_MAP (0x018C + IPU_BASE) -#define DI_DISP2_DB0_MAP (0x0190 + IPU_BASE) -#define DI_DISP2_DB1_MAP (0x0194 + IPU_BASE) -#define DI_DISP2_DB2_MAP (0x0198 + IPU_BASE) -#define DI_DISP2_CB0_MAP (0x019C + IPU_BASE) -#define DI_DISP2_CB1_MAP (0x01A0 + IPU_BASE) -#define DI_DISP2_CB2_MAP (0x01A4 + IPU_BASE) -#define DI_DISP3_B0_MAP (0x01A8 + IPU_BASE) -#define DI_DISP3_B1_MAP (0x01AC + IPU_BASE) -#define DI_DISP3_B2_MAP (0x01B0 + IPU_BASE) -#define DI_DISP_ACC_CC (0x01B4 + IPU_BASE) -#define DI_DISP_LLA_CONF (0x01B8 + IPU_BASE) -#define DI_DISP_LLA_DATA (0x01BC + IPU_BASE) - -/* DI_DISP_SIG_POL bits */ -#define DI_D3_VSYNC_POL (1 << 28) -#define DI_D3_HSYNC_POL (1 << 27) -#define DI_D3_DRDY_SHARP_POL (1 << 26) -#define DI_D3_CLK_POL (1 << 25) -#define DI_D3_DATA_POL (1 << 24) - -/* DI_DISP_IF_CONF bits */ -#define DI_D3_CLK_IDLE (1 << 26) -#define DI_D3_CLK_SEL (1 << 25) -#define DI_D3_DATAMSK (1 << 24) - -#define IOMUX_PADNUM_MASK 0x1ff -#define IOMUX_GPIONUM_SHIFT 9 -#define IOMUX_GPIONUM_MASK (0xff << IOMUX_GPIONUM_SHIFT) - -#define IOMUX_PIN(gpionum, padnum) ((padnum) & IOMUX_PADNUM_MASK) - -#define IOMUX_MODE_L(pin, mode) IOMUX_MODE(((pin) + 0xc) ^ 3, mode) - -struct chan_param_mem_planar { - /* Word 0 */ - u32 xv:10; - u32 yv:10; - u32 xb:12; - - u32 yb:12; - u32 res1:2; - u32 nsb:1; - u32 lnpb:6; - u32 ubo_l:11; - - u32 ubo_h:15; - u32 vbo_l:17; - - u32 vbo_h:9; - u32 res2:3; - u32 fw:12; - u32 fh_l:8; - - u32 fh_h:4; - u32 res3:28; - - /* Word 1 */ - u32 eba0; - - u32 eba1; - - u32 bpp:3; - u32 sl:14; - u32 pfs:3; - u32 bam:3; - u32 res4:2; - u32 npb:6; - u32 res5:1; - - u32 sat:2; - u32 res6:30; -} __attribute__ ((packed)); - -struct chan_param_mem_interleaved { - /* Word 0 */ - u32 xv:10; - u32 yv:10; - u32 xb:12; - - u32 yb:12; - u32 sce:1; - u32 res1:1; - u32 nsb:1; - u32 lnpb:6; - u32 sx:10; - u32 sy_l:1; - - u32 sy_h:9; - u32 ns:10; - u32 sm:10; - u32 sdx_l:3; - - u32 sdx_h:2; - u32 sdy:5; - u32 sdrx:1; - u32 sdry:1; - u32 sdr1:1; - u32 res2:2; - u32 fw:12; - u32 fh_l:8; - - u32 fh_h:4; - u32 res3:28; - - /* Word 1 */ - u32 eba0; - - u32 eba1; - - u32 bpp:3; - u32 sl:14; - u32 pfs:3; - u32 bam:3; - u32 res4:2; - u32 npb:6; - u32 res5:1; - - u32 sat:2; - u32 scc:1; - u32 ofs0:5; - u32 ofs1:5; - u32 ofs2:5; - u32 ofs3:5; - u32 wid0:3; - u32 wid1:3; - u32 wid2:3; - - u32 wid3:3; - u32 dec_sel:1; - u32 res6:28; -} __attribute__ ((packed)); - -union chan_param_mem { - struct chan_param_mem_planar pp; - struct chan_param_mem_interleaved ip; -}; - -/* graphics setup */ -static GraphicDevice panel; -static struct ctfb_res_modes *mode; -static struct ctfb_res_modes var_mode; - -/* - * sdc_init_panel() - initialize a synchronous LCD panel. - * @width: width of panel in pixels. - * @height: height of panel in pixels. - * @di_setup: pixel format of the frame buffer - * @di_panel: either SHARP or normal TFT - * @return: 0 on success or negative error code on failure. - */ -static int sdc_init_panel(u16 width, u16 height, - enum pixel_fmt di_setup, enum ipu_panel di_panel) -{ - u32 reg, div; - uint32_t old_conf; - int clock; - - debug("%s(width=%d, height=%d)\n", __func__, width, height); - - /* Init clocking, the IPU receives its clock from the hsp divder */ - clock = mxc_get_clock(MXC_IPU_CLK); - if (clock < 0) - return -EACCES; - - /* Init panel size and blanking periods */ - reg = width + mode->left_margin + mode->right_margin - 1; - if (reg > 1023) { - printf("mx3fb: Display width too large, coerced to 1023!"); - reg = 1023; - } - reg = ((mode->hsync_len - 1) << 26) | (reg << 16); - writel(reg, SDC_HOR_CONF); - - reg = height + mode->upper_margin + mode->lower_margin - 1; - if (reg > 1023) { - printf("mx3fb: Display height too large, coerced to 1023!"); - reg = 1023; - } - reg = ((mode->vsync_len - 1) << 26) | SDC_V_SYNC_WIDTH_L | (reg << 16); - writel(reg, SDC_VER_CONF); - - switch (di_panel) { - case IPU_PANEL_SHARP_TFT: - writel(0x00FD0102L, SDC_SHARP_CONF_1); - writel(0x00F500F4L, SDC_SHARP_CONF_2); - writel(SDC_COM_SHARP | SDC_COM_TFT_COLOR, SDC_COM_CONF); - /* TODO: probably IF_CONF must be adapted (see below)! */ - break; - case IPU_PANEL_TFT: - writel(SDC_COM_TFT_COLOR, SDC_COM_CONF); - break; - default: - return -EINVAL; - } - - /* - * Calculate divider: The fractional part is 4 bits so simply - * multiple by 2^4 to get it. - * - * Opposed to the kernel driver mode->pixclock is the time of one - * pixel in pico seconds, so: - * pixel_clk = 1e12 / mode->pixclock - * div = ipu_clk * 16 / pixel_clk - * leads to: - * div = ipu_clk * 16 / (1e12 / mode->pixclock) - * or: - * div = ipu_clk * 16 * mode->pixclock / 1e12 - * - * To avoid integer overflows this is split into 2 shifts and - * one divide with sufficient accuracy: - * 16*1024*128*476837 = 0.9999996682e12 - */ - div = ((clock/1024) * (mode->pixclock/128)) / 476837; - debug("hsp_clk is %d, div=%d\n", clock, div); - /* coerce to not less than 4.0, not more than 255.9375 */ - if (div < 0x40) - div = 0x40; - else if (div > 0xFFF) - div = 0xFFF; - /* DISP3_IF_CLK_DOWN_WR is half the divider value and 2 less - * fraction bits. Subtract 1 extra from DISP3_IF_CLK_DOWN_WR - * based on timing debug DISP3_IF_CLK_UP_WR is 0 - */ - writel((((div / 8) - 1) << 22) | div, DI_DISP3_TIME_CONF); - - /* DI settings for display 3: clock idle (bit 26) during vsync */ - old_conf = readl(DI_DISP_IF_CONF) & 0x78FFFFFF; - writel(old_conf | IF_CONF, DI_DISP_IF_CONF); - - /* only set display 3 polarity bits */ - old_conf = readl(DI_DISP_SIG_POL) & 0xE0FFFFFF; - writel(old_conf | mode->sync, DI_DISP_SIG_POL); - - writel(fmt_cfg[di_setup].b0, DI_DISP3_B0_MAP); - writel(fmt_cfg[di_setup].b1, DI_DISP3_B1_MAP); - writel(fmt_cfg[di_setup].b2, DI_DISP3_B2_MAP); - writel(readl(DI_DISP_ACC_CC) | - ((fmt_cfg[di_setup].acc - 1) << 12), DI_DISP_ACC_CC); - - debug("DI_DISP_IF_CONF = 0x%08X\n", readl(DI_DISP_IF_CONF)); - debug("DI_DISP_SIG_POL = 0x%08X\n", readl(DI_DISP_SIG_POL)); - debug("DI_DISP3_TIME_CONF = 0x%08X\n", readl(DI_DISP3_TIME_CONF)); - debug("SDC_HOR_CONF = 0x%08X\n", readl(SDC_HOR_CONF)); - debug("SDC_VER_CONF = 0x%08X\n", readl(SDC_VER_CONF)); - - return 0; -} - -static void ipu_ch_param_set_size(union chan_param_mem *params, - uint pixelfmt, uint16_t width, - uint16_t height, uint16_t stride) -{ - debug("%s(pixelfmt=%d, width=%d, height=%d, stride=%d)\n", - __func__, pixelfmt, width, height, stride); - - params->pp.fw = width - 1; - params->pp.fh_l = height - 1; - params->pp.fh_h = (height - 1) >> 8; - params->pp.sl = stride - 1; - - /* See above, for further formats see the Linux driver */ - switch (pixelfmt) { - case GDF_16BIT_565RGB: - params->ip.bpp = 2; - params->ip.pfs = 4; - params->ip.npb = 7; - params->ip.sat = 2; /* SAT = 32-bit access */ - params->ip.ofs0 = 0; /* Red bit offset */ - params->ip.ofs1 = 5; /* Green bit offset */ - params->ip.ofs2 = 11; /* Blue bit offset */ - params->ip.ofs3 = 16; /* Alpha bit offset */ - params->ip.wid0 = 4; /* Red bit width - 1 */ - params->ip.wid1 = 5; /* Green bit width - 1 */ - params->ip.wid2 = 4; /* Blue bit width - 1 */ - break; - case GDF_32BIT_X888RGB: - params->ip.bpp = 1; /* 24 BPP & RGB PFS */ - params->ip.pfs = 4; - params->ip.npb = 7; - params->ip.sat = 2; /* SAT = 32-bit access */ - params->ip.ofs0 = 16; /* Red bit offset */ - params->ip.ofs1 = 8; /* Green bit offset */ - params->ip.ofs2 = 0; /* Blue bit offset */ - params->ip.ofs3 = 24; /* Alpha bit offset */ - params->ip.wid0 = 7; /* Red bit width - 1 */ - params->ip.wid1 = 7; /* Green bit width - 1 */ - params->ip.wid2 = 7; /* Blue bit width - 1 */ - break; - default: - printf("mx3fb: Pixel format not supported!\n"); - break; - } - - params->pp.nsb = 1; -} - -static void ipu_ch_param_set_buffer(union chan_param_mem *params, - void *buf0, void *buf1) -{ - params->pp.eba0 = (u32)buf0; - params->pp.eba1 = (u32)buf1; -} - -static void ipu_write_param_mem(uint32_t addr, uint32_t *data, - uint32_t num_words) -{ - for (; num_words > 0; num_words--) { - writel(addr, IPU_IMA_ADDR); - writel(*data++, IPU_IMA_DATA); - addr++; - if ((addr & 0x7) == 5) { - addr &= ~0x7; /* set to word 0 */ - addr += 8; /* increment to next row */ - } - } -} - -static uint32_t dma_param_addr(enum ipu_channel channel) -{ - /* Channel Parameter Memory */ - return 0x10000 | (channel << 4); -} - -static void ipu_init_channel_buffer(enum ipu_channel channel, void *fbmem) -{ - union chan_param_mem params = {}; - uint32_t reg; - uint32_t stride_bytes; - - stride_bytes = (panel.plnSizeX * panel.gdfBytesPP + 3) & ~3; - - debug("%s(channel=%d, fbmem=%p)\n", __func__, channel, fbmem); - - /* Build parameter memory data for DMA channel */ - ipu_ch_param_set_size(¶ms, panel.gdfIndex, - panel.plnSizeX, panel.plnSizeY, stride_bytes); - ipu_ch_param_set_buffer(¶ms, fbmem, NULL); - params.pp.bam = 0; - /* Some channels (rotation) have restriction on burst length */ - - switch (channel) { - case IDMAC_SDC_0: - /* In original code only IPU_PIX_FMT_RGB565 was setting burst */ - params.pp.npb = 16 - 1; - break; - default: - break; - } - - ipu_write_param_mem(dma_param_addr(channel), (uint32_t *)¶ms, 10); - - /* Disable double-buffering */ - reg = readl(IPU_CHA_DB_MODE_SEL); - reg &= ~(1UL << channel); - writel(reg, IPU_CHA_DB_MODE_SEL); -} - -static void ipu_channel_set_priority(enum ipu_channel channel, - int prio) -{ - u32 reg = readl(IDMAC_CHA_PRI); - - if (prio) - reg |= 1UL << channel; - else - reg &= ~(1UL << channel); - - writel(reg, IDMAC_CHA_PRI); -} - -/* - * ipu_enable_channel() - enable an IPU channel. - * @channel: channel ID. - * @return: 0 on success or negative error code on failure. - */ -static int ipu_enable_channel(enum ipu_channel channel) -{ - uint32_t reg; - - /* Reset to buffer 0 */ - writel(1UL << channel, IPU_CHA_CUR_BUF); - - switch (channel) { - case IDMAC_SDC_0: - ipu_channel_set_priority(channel, 1); - break; - default: - break; - } - - reg = readl(IDMAC_CHA_EN); - writel(reg | (1UL << channel), IDMAC_CHA_EN); - - return 0; -} - -static int ipu_update_channel_buffer(enum ipu_channel channel, void *buf) -{ - uint32_t reg; - - reg = readl(IPU_CHA_BUF0_RDY); - if (reg & (1UL << channel)) - return -EACCES; - - /* 44.3.3.1.9 - Row Number 1 (WORD1, offset 0) */ - writel(dma_param_addr(channel) + 0x0008UL, IPU_IMA_ADDR); - writel((u32)buf, IPU_IMA_DATA); - - return 0; -} - -static int idmac_tx_submit(enum ipu_channel channel, void *buf) -{ - int ret; - - ipu_init_channel_buffer(channel, buf); - - - /* ipu_idmac.c::ipu_submit_channel_buffers() */ - ret = ipu_update_channel_buffer(channel, buf); - if (ret < 0) - return ret; - - /* ipu_idmac.c::ipu_select_buffer() */ - /* Mark buffer 0 as ready. */ - writel(1UL << channel, IPU_CHA_BUF0_RDY); - - - ret = ipu_enable_channel(channel); - return ret; -} - -static void sdc_enable_channel(void *fbmem) -{ - int ret; - u32 reg; - - ret = idmac_tx_submit(IDMAC_SDC_0, fbmem); - - /* mx3fb.c::sdc_fb_init() */ - if (ret >= 0) { - reg = readl(SDC_COM_CONF); - writel(reg | SDC_COM_BG_EN, SDC_COM_CONF); - } - - /* - * Attention! Without this msleep the channel keeps generating - * interrupts. Next sdc_set_brightness() is going to be called - * from mx3fb_blank(). - */ - udelay(2000); -} - -/* - * mx3fb_set_par() - set framebuffer parameters and change the operating mode. - * @return: 0 on success or negative error code on failure. - * TODO: currently only 666 and TFT as DI setup supported - */ -static int mx3fb_set_par(void) -{ - int ret; - - ret = sdc_init_panel(panel.plnSizeX, panel.plnSizeY, - IPU_PIX_FMT_RGB666, IPU_PANEL_TFT); - if (ret < 0) - return ret; - - writel((mode->left_margin << 16) | mode->upper_margin, SDC_BG_POS); - - return 0; -} - -static void ll_disp3_enable(void *base) -{ - u32 reg; - - debug("%s(base=0x%x)\n", __func__, (u32) base); - /* pcm037.c::mxc_board_init() */ - - /* Display Interface #3 */ - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD0, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD1, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD2, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD3, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD4, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD5, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD6, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD7, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD8, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD9, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD10, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD11, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD12, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD13, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD14, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD15, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD16, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_LD17, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_VSYNC3, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_HSYNC, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_FPSHIFT, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_DRDY0, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_D3_REV, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_CONTRAST, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_D3_SPL, MUX_CTL_FUNC)); - mx31_gpio_mux(IOMUX_MODE_L(MX31_PIN_D3_CLS, MUX_CTL_FUNC)); - - - /* ipu_idmac.c::ipu_probe() */ - - /* Start the clock */ - __REG(CCM_CGR1) = __REG(CCM_CGR1) | (3 << 22); - - - /* ipu_idmac.c::ipu_idmac_init() */ - - /* Service request counter to maximum - shouldn't be needed */ - writel(0x00000070, IDMAC_CONF); - - - /* ipu_idmac.c::ipu_init_channel() */ - - /* Enable IPU sub modules */ - reg = readl(IPU_CONF) | IPU_CONF_SDC_EN | IPU_CONF_DI_EN; - writel(reg, IPU_CONF); - - - /* mx3fb.c::init_fb_chan() */ - - /* set Display Interface clock period */ - writel(0x00100010L, DI_HSP_CLK_PER); - /* Might need to trigger HSP clock change - see 44.3.3.8.5 */ - - - /* mx3fb.c::sdc_set_brightness() */ - - /* This might be board-specific */ - writel(0x03000000UL | 255 << 16, SDC_PWM_CTRL); - - - /* mx3fb.c::sdc_set_global_alpha() */ - - /* Use global - not per-pixel - Alpha-blending */ - reg = readl(SDC_GW_CTRL) & 0x00FFFFFFL; - writel(reg | ((uint32_t) 0xff << 24), SDC_GW_CTRL); - - reg = readl(SDC_COM_CONF); - writel(reg | SDC_COM_GLB_A, SDC_COM_CONF); - - - /* mx3fb.c::sdc_set_color_key() */ - - /* Disable colour-keying for background */ - reg = readl(SDC_COM_CONF) & - ~(SDC_COM_GWSEL | SDC_COM_KEY_COLOR_G); - writel(reg, SDC_COM_CONF); - - - mx3fb_set_par(); - - sdc_enable_channel(base); - - /* - * Linux driver calls sdc_set_brightness() here again, - * once is enough for us - */ - debug("%s() done\n", __func__); -} - -/* ------------------------ public part ------------------- */ -ulong calc_fbsize(void) -{ - return panel.plnSizeX * panel.plnSizeY * panel.gdfBytesPP; -} - -/* - * The current implementation is only tested for GDF_16BIT_565RGB! - * It was switched from the original CONFIG_LCD setup to CONFIG_VIDEO, - * because the lcd code seemed loaded with color table stuff, that - * does not relate to most modern TFTs. cfb_console.c looks more - * straight forward. - * This is the environment setting for the original setup - * "unknown=video=ctfb:x:240,y:320,depth:16,mode:0,pclk:185925,le:9,ri:17, - * up:7,lo:10,hs:1,vs:1,sync:100663296,vmode:0" - * "videomode=unknown" - * - * Settings for VBEST VGG322403 display: - * "videomode=video=ctfb:x:320,y:240,depth:16,mode:0,pclk:156000, - * "le:20,ri:68,up:7,lo:29,hs:30,vs:3,sync:100663296,vmode:0" - * - * Settings for COM57H5M10XRC display: - * "videomode=video=ctfb:x:640,y:480,depth:16,mode:0,pclk:40000, - * "le:120,ri:40,up:35,lo:10,hs:30,vs:3,sync:100663296,vmode:0" - */ -void *video_hw_init(void) -{ - char *penv; - u32 memsize; - unsigned long t1, hsynch, vsynch; - int bits_per_pixel, i, tmp, videomode; - - tmp = 0; - - puts("Video: "); - - videomode = CONFIG_SYS_DEFAULT_VIDEO_MODE; - /* get video mode via environment */ - penv = env_get("videomode"); - if (penv) { - /* decide if it is a string */ - if (penv[0] <= '9') { - videomode = (int)hextoul(penv, NULL); - tmp = 1; - } - } else { - tmp = 1; - } - if (tmp) { - /* parameter are vesa modes */ - /* search params */ - for (i = 0; i < VESA_MODES_COUNT; i++) { - if (vesa_modes[i].vesanr == videomode) - break; - } - if (i == VESA_MODES_COUNT) { - printf("No VESA Mode found, switching to mode 0x%x ", - CONFIG_SYS_DEFAULT_VIDEO_MODE); - i = 0; - } - mode = (struct ctfb_res_modes *) - &res_mode_init[vesa_modes[i].resindex]; - bits_per_pixel = vesa_modes[i].bits_per_pixel; - } else { - mode = (struct ctfb_res_modes *) &var_mode; - bits_per_pixel = video_get_params(mode, penv); - } - - /* calculate hsynch and vsynch freq (info only) */ - t1 = (mode->left_margin + mode->xres + - mode->right_margin + mode->hsync_len) / 8; - t1 *= 8; - t1 *= mode->pixclock; - t1 /= 1000; - hsynch = 1000000000L / t1; - t1 *= (mode->upper_margin + mode->yres + - mode->lower_margin + mode->vsync_len); - t1 /= 1000; - vsynch = 1000000000L / t1; - - /* fill in Graphic device struct */ - sprintf(panel.modeIdent, "%dx%dx%d %ldkHz %ldHz", - mode->xres, mode->yres, - bits_per_pixel, (hsynch / 1000), (vsynch / 1000)); - printf("%s\n", panel.modeIdent); - panel.winSizeX = mode->xres; - panel.winSizeY = mode->yres; - panel.plnSizeX = mode->xres; - panel.plnSizeY = mode->yres; - - switch (bits_per_pixel) { - case 24: - panel.gdfBytesPP = 4; - panel.gdfIndex = GDF_32BIT_X888RGB; - break; - case 16: - panel.gdfBytesPP = 2; - panel.gdfIndex = GDF_16BIT_565RGB; - break; - default: - panel.gdfBytesPP = 1; - panel.gdfIndex = GDF__8BIT_INDEX; - break; - } - - /* set up Hardware */ - memsize = calc_fbsize(); - - debug("%s() allocating %d bytes\n", __func__, memsize); - - /* fill in missing Graphic device struct */ - panel.frameAdrs = (u32) malloc(memsize); - if (panel.frameAdrs == 0) { - printf("%s() malloc(%d) failed\n", __func__, memsize); - return 0; - } - panel.memSize = memsize; - - ll_disp3_enable((void *) panel.frameAdrs); - memset((void *) panel.frameAdrs, 0, memsize); - - debug("%s() done, framebuffer at 0x%x, size=%d cleared\n", - __func__, panel.frameAdrs, memsize); - - return (void *) &panel; -} diff --git a/drivers/video/simplefb.c b/drivers/video/simplefb.c index fd58426cf5d..2b0d8835e38 100644 --- a/drivers/video/simplefb.c +++ b/drivers/video/simplefb.c @@ -50,8 +50,18 @@ static int simple_video_probe(struct udevice *dev) if (strcmp(format, "r5g6b5") == 0) { uc_priv->bpix = VIDEO_BPP16; - } else if (strcmp(format, "a8b8g8r8") == 0) { + } else if (strcmp(format, "a8b8g8r8") == 0 || + strcmp(format, "x8b8g8r8") == 0) { uc_priv->bpix = VIDEO_BPP32; + uc_priv->format = VIDEO_X8B8G8R8; + } else if (strcmp(format, "a8r8g8b8") == 0 || + strcmp(format, "x8r8g8b8") == 0) { + uc_priv->bpix = VIDEO_BPP32; + uc_priv->format = VIDEO_X8R8G8B8; + } else if (strcmp(format, "a2r10g10b10") == 0 || + strcmp(format, "x2r10g10b10") == 0) { + uc_priv->bpix = VIDEO_BPP32; + uc_priv->format = VIDEO_X2R10G10B10; } else { printf("%s: invalid format: %s\n", __func__, format); return -EINVAL; diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c index 4361a58cd7e..5a21f7af668 100644 --- a/drivers/video/sunxi/sunxi_display.c +++ b/drivers/video/sunxi/sunxi_display.c @@ -17,7 +17,6 @@ #include <asm/arch/clock.h> #include <asm/arch/display.h> -#include <asm/arch/gpio.h> #include <asm/arch/lcdc.h> #include <asm/arch/pwm.h> #include <asm/arch/tve.h> @@ -872,11 +871,11 @@ static void sunxi_vga_external_dac_enable(void) static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode) { struct ssd2828_config cfg = { - .csx_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS), - .sck_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK), - .sdi_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI), - .sdo_pin = name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO), - .reset_pin = name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET), + .csx_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_CS), + .sck_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_SCLK), + .sdi_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_MOSI), + .sdo_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SPI_MISO), + .reset_pin = sunxi_name_to_gpio(CONFIG_VIDEO_LCD_SSD2828_RESET), .ssd2828_tx_clk_khz = CONFIG_VIDEO_LCD_SSD2828_TX_CLK * 1000, .ssd2828_color_depth = 24, #ifdef CONFIG_VIDEO_LCD_PANEL_MIPI_4_LANE_513_MBPS_VIA_SSD2828 @@ -902,6 +901,42 @@ static int sunxi_ssd2828_init(const struct ctfb_res_modes *mode) } #endif /* CONFIG_VIDEO_LCD_SSD2828 */ +#ifdef CONFIG_VIDEO_LCD_PANEL_I2C +static void sunxi_panel_i2c_init(struct sunxi_display_priv *sunxi_display) +{ + const char *name = CONFIG_VIDEO_LCD_PANEL_I2C_NAME; + struct udevice *i2c_bus; + int ret; + + ret = uclass_get_device_by_name(UCLASS_I2C, name, &i2c_bus); + if (ret) + return; + + if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) { + /* + * The anx9804 needs 1.8V from eldo3, we do this here + * and not via CONFIG_AXP_ELDO3_VOLT from board_init() + * to avoid turning this on when using hdmi output. + */ + axp_set_eldo(3, 1800); + anx9804_init(i2c_bus, 4, + ANX9804_DATA_RATE_1620M, + sunxi_display->depth); + } + if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) { + struct udevice *chip; + + ret = i2c_get_chip(i2c_bus, 0x5c, 1, &chip); + if (ret) + return; + + dm_i2c_reg_write(chip, 0x04, 0x42); /* Turn on the LCD */ + } +} +#else +static void sunxi_panel_i2c_init(struct sunxi_display_priv *sunxi_display) {} +#endif + static void sunxi_engines_init(void) { sunxi_composer_init(); @@ -936,27 +971,12 @@ static void sunxi_mode_set(struct sunxi_display_priv *sunxi_display, break; case sunxi_monitor_lcd: sunxi_lcdc_panel_enable(); - if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_EDP_4_LANE_1620M_VIA_ANX9804)) { - /* - * The anx9804 needs 1.8V from eldo3, we do this here - * and not via CONFIG_AXP_ELDO3_VOLT from board_init() - * to avoid turning this on when using hdmi output. - */ - axp_set_eldo(3, 1800); - anx9804_init(CONFIG_VIDEO_LCD_I2C_BUS, 4, - ANX9804_DATA_RATE_1620M, - sunxi_display->depth); - } if (IS_ENABLED(CONFIG_VIDEO_LCD_HITACHI_TX18D42VM)) { mdelay(50); /* Wait for lcd controller power on */ hitachi_tx18d42vm_init(); } - if (IS_ENABLED(CONFIG_VIDEO_LCD_TL059WV5C0)) { - unsigned int orig_i2c_bus = i2c_get_bus_num(); - i2c_set_bus_num(CONFIG_VIDEO_LCD_I2C_BUS); - i2c_reg_write(0x5c, 0x04, 0x42); /* Turn on the LCD */ - i2c_set_bus_num(orig_i2c_bus); - } + if (IS_ENABLED(CONFIG_VIDEO_LCD_PANEL_I2C)) + sunxi_panel_i2c_init(sunxi_display); sunxi_composer_mode_set(mode, address, monitor); sunxi_lcdc_tcon0_mode_set(sunxi_display, mode, false); sunxi_composer_enable(); diff --git a/drivers/video/sunxi/sunxi_lcd.c b/drivers/video/sunxi/sunxi_lcd.c index 7a9eba1ed42..8b9c3b2bfa9 100644 --- a/drivers/video/sunxi/sunxi_lcd.c +++ b/drivers/video/sunxi/sunxi_lcd.c @@ -15,7 +15,6 @@ #include <asm/io.h> #include <asm/arch/clock.h> #include <asm/arch/lcdc.h> -#include <asm/arch/gpio.h> #include <asm/global_data.h> #include <asm/gpio.h> diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index 8132efa55a3..f42db40d4cd 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -155,9 +155,14 @@ u32 vid_console_color(struct video_priv *priv, unsigned int idx) break; case VIDEO_BPP32: if (CONFIG_IS_ENABLED(VIDEO_BPP32)) { - return (colors[idx].r << 16) | - (colors[idx].g << 8) | - (colors[idx].b << 0); + if (priv->format == VIDEO_X2R10G10B10) + return (colors[idx].r << 22) | + (colors[idx].g << 12) | + (colors[idx].b << 2); + else + return (colors[idx].r << 16) | + (colors[idx].g << 8) | + (colors[idx].b << 0); } break; default: |