summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/cache/cache-sifive-ccache.c2
-rw-r--r--drivers/clk/clk_fixed_rate.c1
-rw-r--r--drivers/clk/clk_kendryte.c134
-rw-r--r--drivers/clk/rockchip/clk_px30.c3
-rw-r--r--drivers/clk/rockchip/clk_rk3568.c11
-rw-r--r--drivers/clk/sifive/sifive-prci.c6
-rw-r--r--drivers/clk/sunxi/Kconfig14
-rw-r--r--drivers/clk/sunxi/Makefile2
-rw-r--r--drivers/clk/sunxi/clk_a10.c7
-rw-r--r--drivers/clk/sunxi/clk_a10s.c5
-rw-r--r--drivers/clk/sunxi/clk_a23.c8
-rw-r--r--drivers/clk/sunxi/clk_a31.c10
-rw-r--r--drivers/clk/sunxi/clk_a31_r.c59
-rw-r--r--drivers/clk/sunxi/clk_a64.c8
-rw-r--r--drivers/clk/sunxi/clk_a80.c12
-rw-r--r--drivers/clk/sunxi/clk_a83t.c8
-rw-r--r--drivers/clk/sunxi/clk_h3.c8
-rw-r--r--drivers/clk/sunxi/clk_h6.c12
-rw-r--r--drivers/clk/sunxi/clk_h616.c14
-rw-r--r--drivers/clk/sunxi/clk_h6_r.c61
-rw-r--r--drivers/clk/sunxi/clk_r40.c12
-rw-r--r--drivers/clk/sunxi/clk_sunxi.c2
-rw-r--r--drivers/clk/sunxi/clk_v3s.c6
-rw-r--r--drivers/clk/ti/clk-am3-dpll.c131
-rw-r--r--drivers/core/device.c2
-rw-r--r--drivers/core/fdtaddr.c11
-rw-r--r--drivers/core/lists.c4
-rw-r--r--drivers/core/root.c2
-rw-r--r--drivers/fastboot/fb_mmc.c4
-rw-r--r--drivers/gpio/Kconfig8
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/axp_gpio.c1
-rw-r--r--drivers/gpio/max7320_gpio.c113
-rw-r--r--drivers/gpio/sifive-gpio.c6
-rw-r--r--drivers/gpio/sunxi_gpio.c17
-rw-r--r--drivers/i2c/Kconfig16
-rw-r--r--drivers/i2c/Makefile2
-rw-r--r--drivers/i2c/ocores_i2c.c2
-rw-r--r--drivers/i2c/stm32f7_i2c.c91
-rw-r--r--drivers/i2c/sun6i_p2wi.c220
-rw-r--r--drivers/i2c/sun8i_rsb.c281
-rw-r--r--drivers/misc/imx8/scu.c2
-rw-r--r--drivers/mmc/rockchip_sdhci.c3
-rw-r--r--drivers/mmc/sunxi_mmc.c3
-rw-r--r--drivers/mtd/Kconfig7
-rw-r--r--drivers/mtd/nand/raw/Kconfig6
-rw-r--r--drivers/mtd/nand/raw/Makefile1
-rw-r--r--drivers/mtd/nand/raw/mxic_nand.c603
-rw-r--r--drivers/net/macb.c11
-rw-r--r--drivers/net/sun8i_emac.c5
-rw-r--r--drivers/nvme/nvme.c7
-rw-r--r--drivers/pci/pci-aardvark.c199
-rw-r--r--drivers/pci/pci-uclass.c9
-rw-r--r--drivers/pci/pci_auto.c34
-rw-r--r--drivers/pci/pci_auto_common.c2
-rw-r--r--drivers/pci/pcie_dw_meson.c8
-rw-r--r--drivers/phy/marvell/comphy_a3700.c40
-rw-r--r--drivers/phy/marvell/comphy_a3700.h1
-rw-r--r--drivers/phy/phy-stm32-usbphyc.c34
-rw-r--r--drivers/power/axp809.c1
-rw-r--r--drivers/power/axp818.c1
-rw-r--r--drivers/power/pmic/Kconfig84
-rw-r--r--drivers/power/pmic/Makefile1
-rw-r--r--drivers/power/pmic/axp.c38
-rw-r--r--drivers/pwm/Kconfig6
-rw-r--r--drivers/pwm/Makefile1
-rw-r--r--drivers/pwm/pwm-at91.c207
-rw-r--r--drivers/ram/sifive/sifive_ddr.c8
-rw-r--r--drivers/reset/reset-sunxi.c2
-rw-r--r--drivers/rtc/ds1307.c72
-rw-r--r--drivers/serial/Kconfig10
-rw-r--r--drivers/serial/Makefile1
-rw-r--r--drivers/serial/serial-uclass.c2
-rw-r--r--drivers/serial/serial_sbi.c16
-rw-r--r--drivers/spi/rockchip_sfc.c149
-rw-r--r--drivers/spi/spi-sunxi.c2
-rw-r--r--drivers/spi/stm32_spi.c224
-rw-r--r--drivers/sysreset/Kconfig12
-rw-r--r--drivers/sysreset/Makefile1
-rw-r--r--drivers/sysreset/sysreset_sbi.c51
-rw-r--r--drivers/timer/timer-uclass.c2
-rw-r--r--drivers/usb/dwc3/dwc3-meson-gxl.c1
-rw-r--r--drivers/usb/gadget/gadget_chips.h8
-rw-r--r--drivers/usb/host/Kconfig14
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/usb-sandbox.c28
-rw-r--r--drivers/usb/musb-new/sunxi.c2
-rw-r--r--drivers/video/Kconfig16
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/anx9804.c103
-rw-r--r--drivers/video/anx9804.h5
-rw-r--r--drivers/video/cfb_console.c11
-rw-r--r--drivers/video/hitachi_tx18d42vm_lcd.c6
-rw-r--r--drivers/video/mx3fb.c906
-rw-r--r--drivers/video/simplefb.c12
-rw-r--r--drivers/video/sunxi/sunxi_display.c66
-rw-r--r--drivers/video/sunxi/sunxi_lcd.c1
-rw-r--r--drivers/video/vidconsole-uclass.c11
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, &regs->timingr);
/* Enable I2C */
- if (i2c_priv->setup->analog_filter)
+ if (i2c_priv->setup.analog_filter)
clrbits_le32(&regs->cr1, STM32_I2C_CR1_ANFOFF);
else
setbits_le32(&regs->cr1, STM32_I2C_CR1_ANFOFF);
+
+ /* Program the Digital Filter */
+ clrsetbits_le32(&regs->cr1, STM32_I2C_CR1_DNF_MASK,
+ STM32_I2C_CR1_DNF(i2c_priv->setup.dnf));
+
setbits_le32(&regs->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(&params, panel.gdfIndex,
- panel.plnSizeX, panel.plnSizeY, stride_bytes);
- ipu_ch_param_set_buffer(&params, 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 *)&params, 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: