summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/bootcount/Kconfig7
-rw-r--r--drivers/bootcount/Makefile1
-rw-r--r--drivers/bootcount/bootcount.c92
-rw-r--r--drivers/clk/clk_stm32mp1.c13
-rw-r--r--drivers/clk/meson/axg.c7
-rw-r--r--drivers/clk/meson/g12a.c8
-rw-r--r--drivers/clk/meson/gxbb.c7
-rw-r--r--drivers/dma/ti/k3-udma.c7
-rw-r--r--drivers/firmware/firmware-zynqmp.c2
-rw-r--r--drivers/firmware/ti_sci.c77
-rw-r--r--drivers/firmware/ti_sci.h5
-rw-r--r--drivers/i2c/designware_i2c.c18
-rw-r--r--drivers/i2c/designware_i2c.h9
-rw-r--r--drivers/i2c/i2c-gpio.c170
-rw-r--r--drivers/i2c/i2c-uclass.c44
-rw-r--r--drivers/i2c/stm32f7_i2c.c105
-rw-r--r--drivers/misc/Kconfig12
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/esm_pmic.c69
-rw-r--r--drivers/misc/i2c_eeprom.c38
-rw-r--r--drivers/misc/k3_avs.c12
-rw-r--r--drivers/misc/k3_esm.c87
-rw-r--r--drivers/mmc/meson_gx_mmc.c14
-rw-r--r--drivers/mtd/nand/raw/zynq_nand.c25
-rw-r--r--drivers/net/zynq_gem.c28
-rw-r--r--drivers/power/pmic/tps65941.c4
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr.c54
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr.h1
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ddr_regs.h1
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_interactive.c17
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_ram.c34
-rw-r--r--drivers/ram/stm32mp1/stm32mp1_tuning.c223
-rw-r--r--drivers/remoteproc/ti_k3_dsp_rproc.c128
-rw-r--r--drivers/remoteproc/ti_k3_r5f_rproc.c9
-rw-r--r--drivers/serial/serial_zynq.c11
-rw-r--r--drivers/timer/sti-timer.c26
-rw-r--r--drivers/usb/cdns3/core.c15
-rw-r--r--drivers/usb/cdns3/gadget.c2
-rw-r--r--drivers/usb/common/common.c12
-rw-r--r--drivers/usb/dwc3/dwc3-generic.c16
-rw-r--r--drivers/usb/dwc3/dwc3-meson-g12a.c2
-rw-r--r--drivers/usb/gadget/dwc2_udc_otg.c5
-rw-r--r--drivers/usb/host/dwc3-of-simple.c1
-rw-r--r--drivers/usb/host/dwc3-sti-glue.c20
-rw-r--r--drivers/usb/host/ehci-msm.c4
-rw-r--r--drivers/usb/host/ehci-mx6.c2
-rw-r--r--drivers/usb/host/xhci-dwc3.c3
-rw-r--r--drivers/usb/musb-new/ti-musb.c12
-rw-r--r--drivers/video/Kconfig6
-rw-r--r--drivers/video/am335x-fb.c567
-rw-r--r--drivers/video/am335x-fb.h16
-rw-r--r--drivers/video/sunxi/sunxi_display.c4
-rw-r--r--drivers/watchdog/Kconfig9
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/cdns_wdt.c2
-rw-r--r--drivers/watchdog/xilinx_wwdt.c179
57 files changed, 1731 insertions, 517 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 23501fd743..4208750428 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -107,7 +107,6 @@ obj-y += reset/
obj-y += input/
# SOC specific infrastructure drivers.
obj-y += smem/
-obj-y += soc/
obj-y += thermal/
obj-$(CONFIG_TEE) += tee/
obj-y += axi/
@@ -119,3 +118,5 @@ obj-$(CONFIG_MACH_PIC32) += ddr/microchip/
obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock/
obj-$(CONFIG_DM_RNG) += rng/
endif
+
+obj-y += soc/
diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig
index 0e506c9ea2..0356f8ba18 100644
--- a/drivers/bootcount/Kconfig
+++ b/drivers/bootcount/Kconfig
@@ -106,6 +106,13 @@ config DM_BOOTCOUNT_I2C_EEPROM
pointing to the underlying i2c eeprom device) and an optional 'offset'
property are supported.
+config BOOTCOUNT_MEM
+ bool "Support memory based bootcounter"
+ help
+ Enabling Memory based bootcount, typically in a SoC register which
+ is not cleared on softreset.
+ compatible = "u-boot,bootcount";
+
endmenu
endif
diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile
index 73ccfb5a08..059d40d16b 100644
--- a/drivers/bootcount/Makefile
+++ b/drivers/bootcount/Makefile
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
obj-$(CONFIG_BOOTCOUNT_GENERIC) += bootcount.o
+obj-$(CONFIG_BOOTCOUNT_MEM) += bootcount.o
obj-$(CONFIG_BOOTCOUNT_AT91) += bootcount_at91.o
obj-$(CONFIG_BOOTCOUNT_AM33XX) += bootcount_davinci.o
obj-$(CONFIG_BOOTCOUNT_RAM) += bootcount_ram.o
diff --git a/drivers/bootcount/bootcount.c b/drivers/bootcount/bootcount.c
index 7a6d03dcca..655dfaf59c 100644
--- a/drivers/bootcount/bootcount.c
+++ b/drivers/bootcount/bootcount.c
@@ -8,6 +8,7 @@
#include <cpu_func.h>
#include <linux/compiler.h>
+#if !defined(CONFIG_DM_BOOTCOUNT)
/* Now implement the generic default functions */
__weak void bootcount_store(ulong a)
{
@@ -49,3 +50,94 @@ __weak ulong bootcount_load(void)
return raw_bootcount_load(reg);
#endif /* defined(CONFIG_SYS_BOOTCOUNT_SINGLEWORD) */
}
+#else
+#include <dm.h>
+
+/*
+ * struct bootcount_mem_priv - private bootcount mem driver data
+ *
+ * @base: base address used for bootcounter
+ * @singleword: if true use only one 32 bit word for bootcounter
+ */
+struct bootcount_mem_priv {
+ phys_addr_t base;
+ bool singleword;
+};
+
+static int bootcount_mem_get(struct udevice *dev, u32 *a)
+{
+ struct bootcount_mem_priv *priv = dev_get_priv(dev);
+ void *reg = (void *)priv->base;
+ u32 magic = CONFIG_SYS_BOOTCOUNT_MAGIC;
+
+ if (priv->singleword) {
+ u32 tmp = raw_bootcount_load(reg);
+
+ if ((tmp & 0xffff0000) != (magic & 0xffff0000))
+ return -ENODEV;
+
+ *a = (tmp & 0x0000ffff);
+ } else {
+ if (raw_bootcount_load(reg + 4) != magic)
+ return -ENODEV;
+
+ *a = raw_bootcount_load(reg);
+ }
+
+ return 0;
+};
+
+static int bootcount_mem_set(struct udevice *dev, const u32 a)
+{
+ struct bootcount_mem_priv *priv = dev_get_priv(dev);
+ void *reg = (void *)priv->base;
+ u32 magic = CONFIG_SYS_BOOTCOUNT_MAGIC;
+ uintptr_t flush_start = rounddown(priv->base,
+ CONFIG_SYS_CACHELINE_SIZE);
+ uintptr_t flush_end;
+
+ if (priv->singleword) {
+ raw_bootcount_store(reg, (magic & 0xffff0000) | a);
+ flush_end = roundup(priv->base + 4,
+ CONFIG_SYS_CACHELINE_SIZE);
+ } else {
+ raw_bootcount_store(reg, a);
+ raw_bootcount_store(reg + 4, magic);
+ flush_end = roundup(priv->base + 8,
+ CONFIG_SYS_CACHELINE_SIZE);
+ }
+ flush_dcache_range(flush_start, flush_end);
+
+ return 0;
+};
+
+static const struct bootcount_ops bootcount_mem_ops = {
+ .get = bootcount_mem_get,
+ .set = bootcount_mem_set,
+};
+
+static int bootcount_mem_probe(struct udevice *dev)
+{
+ struct bootcount_mem_priv *priv = dev_get_priv(dev);
+
+ priv->base = (phys_addr_t)dev_read_addr(dev);
+ if (dev_read_bool(dev, "single-word"))
+ priv->singleword = true;
+
+ return 0;
+}
+
+static const struct udevice_id bootcount_mem_ids[] = {
+ { .compatible = "u-boot,bootcount" },
+ { }
+};
+
+U_BOOT_DRIVER(bootcount_mem) = {
+ .name = "bootcount-mem",
+ .id = UCLASS_BOOTCOUNT,
+ .priv_auto_alloc_size = sizeof(struct bootcount_mem_priv),
+ .probe = bootcount_mem_probe,
+ .of_match = bootcount_mem_ids,
+ .ops = &bootcount_mem_ops,
+};
+#endif
diff --git a/drivers/clk/clk_stm32mp1.c b/drivers/clk/clk_stm32mp1.c
index fd8c821e48..52bd8e96f3 100644
--- a/drivers/clk/clk_stm32mp1.c
+++ b/drivers/clk/clk_stm32mp1.c
@@ -95,6 +95,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define RCC_I2C12CKSELR 0x8C0
#define RCC_I2C35CKSELR 0x8C4
#define RCC_SPI2S1CKSELR 0x8D8
+#define RCC_SPI45CKSELR 0x8E0
#define RCC_UART6CKSELR 0x8E4
#define RCC_UART24CKSELR 0x8E8
#define RCC_UART35CKSELR 0x8EC
@@ -304,6 +305,7 @@ enum stm32mp1_parent_sel {
_DSI_SEL,
_ADC12_SEL,
_SPI1_SEL,
+ _SPI45_SEL,
_RTC_SEL,
_PARENT_SEL_NB,
_UNKNOWN_SEL = 0xff,
@@ -527,6 +529,7 @@ static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = {
STM32MP1_CLK_SET_CLR(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 8, SPI1_K, _SPI1_SEL),
+ STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 10, SPI5_K, _SPI45_SEL),
STM32MP1_CLK_SET_CLR(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL),
STM32MP1_CLK_SET_CLR_F(RCC_MP_APB3ENSETR, 13, VREF, _PCLK3),
@@ -603,6 +606,8 @@ static const u8 dsi_parents[] = {_DSI_PHY, _PLL4_P};
static const u8 adc_parents[] = {_PLL4_R, _CK_PER, _PLL3_Q};
static const u8 spi_parents[] = {_PLL4_P, _PLL3_Q, _I2S_CKIN, _CK_PER,
_PLL3_R};
+static const u8 spi45_parents[] = {_PCLK2, _PLL4_Q, _HSI_KER, _CSI_KER,
+ _HSE_KER};
static const u8 rtc_parents[] = {_UNKNOWN_ID, _LSE, _LSI, _HSE};
static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
@@ -621,14 +626,15 @@ static const struct stm32mp1_clk_sel stm32mp1_clk_sel[_PARENT_SEL_NB] = {
STM32MP1_CLK_PARENT(_SDMMC3_SEL, RCC_SDMMC3CKSELR, 0, 0x7,
sdmmc3_parents),
STM32MP1_CLK_PARENT(_ETH_SEL, RCC_ETHCKSELR, 0, 0x3, eth_parents),
- STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0xf, qspi_parents),
- STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0xf, fmc_parents),
+ STM32MP1_CLK_PARENT(_QSPI_SEL, RCC_QSPICKSELR, 0, 0x3, qspi_parents),
+ STM32MP1_CLK_PARENT(_FMC_SEL, RCC_FMCCKSELR, 0, 0x3, fmc_parents),
STM32MP1_CLK_PARENT(_USBPHY_SEL, RCC_USBCKSELR, 0, 0x3, usbphy_parents),
STM32MP1_CLK_PARENT(_USBO_SEL, RCC_USBCKSELR, 4, 0x1, usbo_parents),
STM32MP1_CLK_PARENT(_STGEN_SEL, RCC_STGENCKSELR, 0, 0x3, stgen_parents),
STM32MP1_CLK_PARENT(_DSI_SEL, RCC_DSICKSELR, 0, 0x1, dsi_parents),
- STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x1, adc_parents),
+ STM32MP1_CLK_PARENT(_ADC12_SEL, RCC_ADCCKSELR, 0, 0x3, adc_parents),
STM32MP1_CLK_PARENT(_SPI1_SEL, RCC_SPI2S1CKSELR, 0, 0x7, spi_parents),
+ STM32MP1_CLK_PARENT(_SPI45_SEL, RCC_SPI45CKSELR, 0, 0x7, spi45_parents),
STM32MP1_CLK_PARENT(_RTC_SEL, RCC_BDCR, RCC_BDCR_RTCSRC_SHIFT,
(RCC_BDCR_RTCSRC_MASK >> RCC_BDCR_RTCSRC_SHIFT),
rtc_parents),
@@ -747,6 +753,7 @@ char * const stm32mp1_clk_parent_sel_name[_PARENT_SEL_NB] = {
[_DSI_SEL] = "DSI",
[_ADC12_SEL] = "ADC12",
[_SPI1_SEL] = "SPI1",
+ [_SPI45_SEL] = "SPI45",
[_RTC_SEL] = "RTC",
};
diff --git a/drivers/clk/meson/axg.c b/drivers/clk/meson/axg.c
index 7035b59a13..4b0028d04b 100644
--- a/drivers/clk/meson/axg.c
+++ b/drivers/clk/meson/axg.c
@@ -291,6 +291,13 @@ static int meson_clk_probe(struct udevice *dev)
if (IS_ERR(priv->map))
return PTR_ERR(priv->map);
+ /*
+ * Depending on the boot src, the state of the MMC clock might
+ * be different. Reset it to make sure we won't get stuck
+ */
+ regmap_write(priv->map, HHI_NAND_CLK_CNTL, 0);
+ regmap_write(priv->map, HHI_SD_EMMC_CLK_CNTL, 0);
+
debug("meson-clk-axg: probed\n");
return 0;
diff --git a/drivers/clk/meson/g12a.c b/drivers/clk/meson/g12a.c
index 686d94ebfe..c1976aa1ef 100644
--- a/drivers/clk/meson/g12a.c
+++ b/drivers/clk/meson/g12a.c
@@ -804,6 +804,7 @@ static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id)
break;
case CLKID_PCIE_PLL:
rate = meson_pcie_pll_get_rate(clk);
+ break;
case CLKID_VPU_0:
rate = meson_div_get_rate(clk, CLKID_VPU_0_DIV);
break;
@@ -977,6 +978,13 @@ static int meson_clk_probe(struct udevice *dev)
if (IS_ERR(priv->map))
return PTR_ERR(priv->map);
+ /*
+ * Depending on the boot src, the state of the MMC clock might
+ * be different. Reset it to make sure we won't get stuck
+ */
+ regmap_write(priv->map, HHI_NAND_CLK_CNTL, 0);
+ regmap_write(priv->map, HHI_SD_EMMC_CLK_CNTL, 0);
+
debug("meson-clk-g12a: probed\n");
return 0;
diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c
index e781e08d9d..5ef4dd794d 100644
--- a/drivers/clk/meson/gxbb.c
+++ b/drivers/clk/meson/gxbb.c
@@ -887,6 +887,13 @@ static int meson_clk_probe(struct udevice *dev)
if (IS_ERR(priv->map))
return PTR_ERR(priv->map);
+ /*
+ * Depending on the boot src, the state of the MMC clock might
+ * be different. Reset it to make sure we won't get stuck
+ */
+ regmap_write(priv->map, HHI_NAND_CLK_CNTL, 0);
+ regmap_write(priv->map, HHI_SD_EMMC_CLK_CNTL, 0);
+
debug("meson-clk: probed\n");
return 0;
diff --git a/drivers/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index e587f1fcb2..a0e536ae5e 100644
--- a/drivers/dma/ti/k3-udma.c
+++ b/drivers/dma/ti/k3-udma.c
@@ -938,7 +938,9 @@ static int udma_alloc_rchan_sci_req(struct udma_chan *uc)
req.valid_params = TI_SCI_MSG_VALUE_RM_UDMAP_CH_FETCH_SIZE_VALID |
TI_SCI_MSG_VALUE_RM_UDMAP_CH_CQ_QNUM_VALID |
- TI_SCI_MSG_VALUE_RM_UDMAP_CH_CHAN_TYPE_VALID;
+ TI_SCI_MSG_VALUE_RM_UDMAP_CH_CHAN_TYPE_VALID |
+ TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_START_VALID |
+ TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_CNT_VALID;
req.nav_id = tisci_rm->tisci_dev_id;
req.index = uc->rchan->id;
req.rx_chan_type = mode;
@@ -954,9 +956,6 @@ static int udma_alloc_rchan_sci_req(struct udma_chan *uc)
if (uc->rflow->id != uc->rchan->id && uc->dir != DMA_MEM_TO_MEM) {
req.flowid_start = uc->rflow->id;
req.flowid_cnt = 1;
- req.valid_params |=
- TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_START_VALID |
- TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_CNT_VALID;
}
ret = tisci_rm->tisci_udmap_ops->rx_ch_cfg(tisci_rm->tisci, &req);
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index 2a2aa2f4f1..c37642569d 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -51,7 +51,7 @@ static int ipi_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen)
static int send_req(const u32 *req, size_t req_len, u32 *res, size_t res_maxlen)
{
- if (IS_ENABLED(CONFIG_SPL_BUILD))
+ if (IS_ENABLED(CONFIG_SPL_BUILD) || current_el() == 3)
return ipi_req(req, req_len, res, res_maxlen);
return xilinx_pm_request(req[0], 0, 0, 0, 0, res);
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 99b2e5dfed..c3f95b252f 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -2364,82 +2364,6 @@ fail:
return ret;
}
-/**
- * ti_sci_cmd_ring_get_config() - get RA ring configuration
- * @handle: pointer to TI SCI handle
- * @nav_id: Device ID of Navigator Subsystem from which the ring is allocated
- * @index: Ring index.
- * @addr_lo: returns ring's base address lo 32 bits
- * @addr_hi: returns ring's base address hi 32 bits
- * @count: returns number of ring elements.
- * @mode: returns mode of the ring
- * @size: returns ring element size.
- * @order_id: returns ring's bus order ID.
- *
- * Return: 0 if all went well, else returns appropriate error value.
- *
- * See @ti_sci_msg_rm_ring_get_cfg_req for more info.
- */
-static int ti_sci_cmd_ring_get_config(const struct ti_sci_handle *handle,
- u32 nav_id, u32 index, u8 *mode,
- u32 *addr_lo, u32 *addr_hi,
- u32 *count, u8 *size, u8 *order_id)
-{
- struct ti_sci_msg_rm_ring_get_cfg_resp *resp;
- struct ti_sci_msg_rm_ring_get_cfg_req req;
- struct ti_sci_xfer *xfer;
- struct ti_sci_info *info;
- int ret = 0;
-
- if (IS_ERR(handle))
- return PTR_ERR(handle);
- if (!handle)
- return -EINVAL;
-
- info = handle_to_ti_sci_info(handle);
-
- xfer = ti_sci_setup_one_xfer(info, TI_SCI_MSG_RM_RING_GET_CFG,
- TI_SCI_FLAG_REQ_ACK_ON_PROCESSED,
- (u32 *)&req, sizeof(req), sizeof(*resp));
- if (IS_ERR(xfer)) {
- ret = PTR_ERR(xfer);
- dev_err(info->dev,
- "RM_RA:Message get config failed(%d)\n", ret);
- return ret;
- }
- req.nav_id = nav_id;
- req.index = index;
-
- ret = ti_sci_do_xfer(info, xfer);
- if (ret) {
- dev_err(info->dev, "RM_RA:Mbox get config send fail %d\n", ret);
- goto fail;
- }
-
- resp = (struct ti_sci_msg_rm_ring_get_cfg_resp *)xfer->tx_message.buf;
-
- if (!ti_sci_is_response_ack(resp)) {
- ret = -ENODEV;
- } else {
- if (mode)
- *mode = resp->mode;
- if (addr_lo)
- *addr_lo = resp->addr_lo;
- if (addr_hi)
- *addr_hi = resp->addr_hi;
- if (count)
- *count = resp->count;
- if (size)
- *size = resp->size;
- if (order_id)
- *order_id = resp->order_id;
- };
-
-fail:
- dev_dbg(info->dev, "RM_RA:get config ring %u ret:%d\n", index, ret);
- return ret;
-}
-
static int ti_sci_cmd_rm_psil_pair(const struct ti_sci_handle *handle,
u32 nav_id, u32 src_thread, u32 dst_thread)
{
@@ -2948,7 +2872,6 @@ static void ti_sci_setup_ops(struct ti_sci_info *info)
pops->proc_shutdown_no_wait = ti_sci_cmd_proc_shutdown_no_wait;
rops->config = ti_sci_cmd_ring_config;
- rops->get_config = ti_sci_cmd_ring_get_config;
psilops->pair = ti_sci_cmd_rm_psil_pair;
psilops->unpair = ti_sci_cmd_rm_psil_unpair;
diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h
index 69ff74d6a9..24b4d1c794 100644
--- a/drivers/firmware/ti_sci.h
+++ b/drivers/firmware/ti_sci.h
@@ -58,7 +58,6 @@
/* NAVSS resource management */
/* Ringacc requests */
#define TI_SCI_MSG_RM_RING_CFG 0x1110
-#define TI_SCI_MSG_RM_RING_GET_CFG 0x1111
/* PSI-L requests */
#define TI_SCI_MSG_RM_PSIL_PAIR 0x1280
@@ -72,13 +71,9 @@
#define TI_SCI_MSG_RM_UDMAP_OPT_FLOW_CFG 0x1221
#define TISCI_MSG_RM_UDMAP_TX_CH_CFG 0x1205
-#define TISCI_MSG_RM_UDMAP_TX_CH_GET_CFG 0x1206
#define TISCI_MSG_RM_UDMAP_RX_CH_CFG 0x1215
-#define TISCI_MSG_RM_UDMAP_RX_CH_GET_CFG 0x1216
#define TISCI_MSG_RM_UDMAP_FLOW_CFG 0x1230
#define TISCI_MSG_RM_UDMAP_FLOW_SIZE_THRESH_CFG 0x1231
-#define TISCI_MSG_RM_UDMAP_FLOW_GET_CFG 0x1232
-#define TISCI_MSG_RM_UDMAP_FLOW_SIZE_THRESH_GET_CFG 0x1233
#define TISCI_MSG_FWL_SET 0x9000
#define TISCI_MSG_FWL_GET 0x9001
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index 0b5e70af59..088a6f3efb 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -203,14 +203,16 @@ static int calc_bus_speed(struct dw_i2c *priv, int speed, ulong bus_clk,
const struct dw_scl_sda_cfg *scl_sda_cfg = NULL;
struct i2c_regs *regs = priv->regs;
enum i2c_speed_mode i2c_spd;
+ u32 comp_param1;
int spk_cnt;
int ret;
+ comp_param1 = readl(&regs->comp_param1);
+
if (priv)
scl_sda_cfg = priv->scl_sda_cfg;
/* Allow high speed if there is no config, or the config allows it */
- if (speed >= I2C_SPEED_HIGH_RATE &&
- (!scl_sda_cfg || scl_sda_cfg->has_high_speed))
+ if (speed >= I2C_SPEED_HIGH_RATE)
i2c_spd = IC_SPEED_MODE_HIGH;
else if (speed >= I2C_SPEED_FAST_PLUS_RATE)
i2c_spd = IC_SPEED_MODE_FAST_PLUS;
@@ -219,6 +221,13 @@ static int calc_bus_speed(struct dw_i2c *priv, int speed, ulong bus_clk,
else
i2c_spd = IC_SPEED_MODE_STANDARD;
+ /* Check is high speed possible and fall back to fast mode if not */
+ if (i2c_spd == IC_SPEED_MODE_HIGH) {
+ if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK)
+ != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH)
+ i2c_spd = IC_SPEED_MODE_FAST;
+ }
+
/* Get the proper spike-suppression count based on target speed */
if (!priv || !priv->has_spk_cnt)
spk_cnt = 0;
@@ -231,6 +240,9 @@ static int calc_bus_speed(struct dw_i2c *priv, int speed, ulong bus_clk,
if (i2c_spd == IC_SPEED_MODE_STANDARD) {
config->scl_hcnt = scl_sda_cfg->ss_hcnt;
config->scl_lcnt = scl_sda_cfg->ss_lcnt;
+ } else if (i2c_spd == IC_SPEED_MODE_HIGH) {
+ config->scl_hcnt = scl_sda_cfg->hs_hcnt;
+ config->scl_lcnt = scl_sda_cfg->hs_lcnt;
} else {
config->scl_hcnt = scl_sda_cfg->fs_hcnt;
config->scl_lcnt = scl_sda_cfg->fs_lcnt;
@@ -274,7 +286,7 @@ static int _dw_i2c_set_bus_speed(struct dw_i2c *priv, struct i2c_regs *i2c_base,
switch (config.speed_mode) {
case IC_SPEED_MODE_HIGH:
- cntl |= IC_CON_SPD_SS;
+ cntl |= IC_CON_SPD_HS;
writel(config.scl_hcnt, &i2c_base->ic_hs_scl_hcnt);
writel(config.scl_lcnt, &i2c_base->ic_hs_scl_lcnt);
break;
diff --git a/drivers/i2c/designware_i2c.h b/drivers/i2c/designware_i2c.h
index 61a882cb65..7ee236193d 100644
--- a/drivers/i2c/designware_i2c.h
+++ b/drivers/i2c/designware_i2c.h
@@ -138,22 +138,27 @@ struct i2c_regs {
#define IC_STATUS_TFNF 0x0002
#define IC_STATUS_ACT 0x0001
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3))
+#define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK (BIT(2) | BIT(3))
+
/**
* struct dw_scl_sda_cfg - I2C timing configuration
*
- * @has_high_speed: Support high speed (3.4Mbps)
* @ss_hcnt: Standard speed high time in ns
* @fs_hcnt: Fast speed high time in ns
+ * @hs_hcnt: High speed high time in ns
* @ss_lcnt: Standard speed low time in ns
* @fs_lcnt: Fast speed low time in ns
+ * @hs_lcnt: High speed low time in ns
* @sda_hold: SDA hold time
*/
struct dw_scl_sda_cfg {
- bool has_high_speed;
u32 ss_hcnt;
u32 fs_hcnt;
+ u32 hs_hcnt;
u32 ss_lcnt;
u32 fs_lcnt;
+ u32 hs_lcnt;
u32 sda_hold;
};
diff --git a/drivers/i2c/i2c-gpio.c b/drivers/i2c/i2c-gpio.c
index 4e8fa21473..07fdd343f2 100644
--- a/drivers/i2c/i2c-gpio.c
+++ b/drivers/i2c/i2c-gpio.c
@@ -32,23 +32,50 @@ struct i2c_gpio_bus {
int udelay;
/* sda, scl */
struct gpio_desc gpios[PIN_COUNT];
+
+ int (*get_sda)(struct i2c_gpio_bus *bus);
+ void (*set_sda)(struct i2c_gpio_bus *bus, int bit);
+ void (*set_scl)(struct i2c_gpio_bus *bus, int bit);
};
-static int i2c_gpio_sda_get(struct gpio_desc *sda)
+static int i2c_gpio_sda_get(struct i2c_gpio_bus *bus)
{
+ struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+
return dm_gpio_get_value(sda);
}
-static void i2c_gpio_sda_set(struct gpio_desc *sda, int bit)
+static void i2c_gpio_sda_set(struct i2c_gpio_bus *bus, int bit)
{
+ struct gpio_desc *sda = &bus->gpios[PIN_SDA];
+
if (bit)
dm_gpio_set_dir_flags(sda, GPIOD_IS_IN);
else
dm_gpio_set_dir_flags(sda, GPIOD_IS_OUT);
}
-static void i2c_gpio_scl_set(struct gpio_desc *scl, int bit)
+static void i2c_gpio_scl_set(struct i2c_gpio_bus *bus, int bit)
{
+ struct gpio_desc *scl = &bus->gpios[PIN_SCL];
+ int count = 0;
+
+ if (bit) {
+ dm_gpio_set_dir_flags(scl, GPIOD_IS_IN);
+ while (!dm_gpio_get_value(scl) && count++ < 100000)
+ udelay(1);
+
+ if (!dm_gpio_get_value(scl))
+ pr_err("timeout waiting on slave to release scl\n");
+ } else {
+ dm_gpio_set_dir_flags(scl, GPIOD_IS_OUT);
+ }
+}
+
+/* variant for output only gpios which cannot support clock stretching */
+static void i2c_gpio_scl_set_output_only(struct i2c_gpio_bus *bus, int bit)
+{
+ struct gpio_desc *scl = &bus->gpios[PIN_SCL];
ulong flags = GPIOD_IS_OUT;
if (bit)
@@ -56,65 +83,60 @@ static void i2c_gpio_scl_set(struct gpio_desc *scl, int bit)
dm_gpio_set_dir_flags(scl, flags);
}
-static void i2c_gpio_write_bit(struct gpio_desc *scl, struct gpio_desc *sda,
- int delay, uchar bit)
+static void i2c_gpio_write_bit(struct i2c_gpio_bus *bus, int delay, uchar bit)
{
- i2c_gpio_scl_set(scl, 0);
+ bus->set_scl(bus, 0);
udelay(delay);
- i2c_gpio_sda_set(sda, bit);
+ bus->set_sda(bus, bit);
udelay(delay);
- i2c_gpio_scl_set(scl, 1);
+ bus->set_scl(bus, 1);
udelay(2 * delay);
}
-static int i2c_gpio_read_bit(struct gpio_desc *scl, struct gpio_desc *sda,
- int delay)
+static int i2c_gpio_read_bit(struct i2c_gpio_bus *bus, int delay)
{
int value;
- i2c_gpio_scl_set(scl, 1);
+ bus->set_scl(bus, 1);
udelay(delay);
- value = i2c_gpio_sda_get(sda);
+ value = bus->get_sda(bus);
udelay(delay);
- i2c_gpio_scl_set(scl, 0);
+ bus->set_scl(bus, 0);
udelay(2 * delay);
return value;
}
/* START: High -> Low on SDA while SCL is High */
-static void i2c_gpio_send_start(struct gpio_desc *scl, struct gpio_desc *sda,
- int delay)
+static void i2c_gpio_send_start(struct i2c_gpio_bus *bus, int delay)
{
udelay(delay);
- i2c_gpio_sda_set(sda, 1);
+ bus->set_sda(bus, 1);
udelay(delay);
- i2c_gpio_scl_set(scl, 1);
+ bus->set_scl(bus, 1);
udelay(delay);
- i2c_gpio_sda_set(sda, 0);
+ bus->set_sda(bus, 0);
udelay(delay);
}
/* STOP: Low -> High on SDA while SCL is High */
-static void i2c_gpio_send_stop(struct gpio_desc *scl, struct gpio_desc *sda,
- int delay)
+static void i2c_gpio_send_stop(struct i2c_gpio_bus *bus, int delay)
{
- i2c_gpio_scl_set(scl, 0);
+ bus->set_scl(bus, 0);
udelay(delay);
- i2c_gpio_sda_set(sda, 0);
+ bus->set_sda(bus, 0);
udelay(delay);
- i2c_gpio_scl_set(scl, 1);
+ bus->set_scl(bus, 1);
udelay(delay);
- i2c_gpio_sda_set(sda, 1);
+ bus->set_sda(bus, 1);
udelay(delay);
}
/* ack should be I2C_ACK or I2C_NOACK */
-static void i2c_gpio_send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
- int delay, int ack)
+static void i2c_gpio_send_ack(struct i2c_gpio_bus *bus, int delay, int ack)
{
- i2c_gpio_write_bit(scl, sda, delay, ack);
- i2c_gpio_scl_set(scl, 0);
+ i2c_gpio_write_bit(bus, delay, ack);
+ bus->set_scl(bus, 0);
udelay(delay);
}
@@ -123,44 +145,41 @@ static void i2c_gpio_send_ack(struct gpio_desc *scl, struct gpio_desc *sda,
* to clock any confused device back into an idle state. Also send a
* <stop> at the end of the sequence for belts & suspenders.
*/
-static void i2c_gpio_send_reset(struct gpio_desc *scl, struct gpio_desc *sda,
- int delay)
+static void i2c_gpio_send_reset(struct i2c_gpio_bus *bus, int delay)
{
int j;
for (j = 0; j < 9; j++)
- i2c_gpio_write_bit(scl, sda, delay, 1);
+ i2c_gpio_write_bit(bus, delay, 1);
- i2c_gpio_send_stop(scl, sda, delay);
+ i2c_gpio_send_stop(bus, delay);
}
/* Set sda high with low clock, before reading slave data */
-static void i2c_gpio_sda_high(struct gpio_desc *scl, struct gpio_desc *sda,
- int delay)
+static void i2c_gpio_sda_high(struct i2c_gpio_bus *bus, int delay)
{
- i2c_gpio_scl_set(scl, 0);
+ bus->set_scl(bus, 0);
udelay(delay);
- i2c_gpio_sda_set(sda, 1);
+ bus->set_sda(bus, 1);
udelay(delay);
}
/* Send 8 bits and look for an acknowledgement */
-static int i2c_gpio_write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
- int delay, uchar data)
+static int i2c_gpio_write_byte(struct i2c_gpio_bus *bus, int delay, uchar data)
{
int j;
int nack;
for (j = 0; j < 8; j++) {
- i2c_gpio_write_bit(scl, sda, delay, data & 0x80);
+ i2c_gpio_write_bit(bus, delay, data & 0x80);
data <<= 1;
}
udelay(delay);
/* Look for an <ACK>(negative logic) and return it */
- i2c_gpio_sda_high(scl, sda, delay);
- nack = i2c_gpio_read_bit(scl, sda, delay);
+ i2c_gpio_sda_high(bus, delay);
+ nack = i2c_gpio_read_bit(bus, delay);
return nack; /* not a nack is an ack */
}
@@ -169,31 +188,29 @@ static int i2c_gpio_write_byte(struct gpio_desc *scl, struct gpio_desc *sda,
* if ack == I2C_ACK, ACK the byte so can continue reading, else
* send I2C_NOACK to end the read.
*/
-static uchar i2c_gpio_read_byte(struct gpio_desc *scl, struct gpio_desc *sda,
- int delay, int ack)
+static uchar i2c_gpio_read_byte(struct i2c_gpio_bus *bus, int delay, int ack)
{
int data;
int j;
- i2c_gpio_sda_high(scl, sda, delay);
+ i2c_gpio_sda_high(bus, delay);
data = 0;
for (j = 0; j < 8; j++) {
data <<= 1;
- data |= i2c_gpio_read_bit(scl, sda, delay);
+ data |= i2c_gpio_read_bit(bus, delay);
}
- i2c_gpio_send_ack(scl, sda, delay, ack);
+ i2c_gpio_send_ack(bus, delay, ack);
return data;
}
/* send start and the slave chip address */
-int i2c_send_slave_addr(struct gpio_desc *scl, struct gpio_desc *sda, int delay,
- uchar chip)
+int i2c_send_slave_addr(struct i2c_gpio_bus *bus, int delay, uchar chip)
{
- i2c_gpio_send_start(scl, sda, delay);
+ i2c_gpio_send_start(bus, delay);
- if (i2c_gpio_write_byte(scl, sda, delay, chip)) {
- i2c_gpio_send_stop(scl, sda, delay);
+ if (i2c_gpio_write_byte(bus, delay, chip)) {
+ i2c_gpio_send_stop(bus, delay);
return -EIO;
}
@@ -204,29 +221,27 @@ static int i2c_gpio_write_data(struct i2c_gpio_bus *bus, uchar chip,
uchar *buffer, int len,
bool end_with_repeated_start)
{
- struct gpio_desc *scl = &bus->gpios[PIN_SCL];
- struct gpio_desc *sda = &bus->gpios[PIN_SDA];
unsigned int delay = bus->udelay;
int failures = 0;
debug("%s: chip %x buffer %p len %d\n", __func__, chip, buffer, len);
- if (i2c_send_slave_addr(scl, sda, delay, chip << 1)) {
+ if (i2c_send_slave_addr(bus, delay, chip << 1)) {
debug("i2c_write, no chip responded %02X\n", chip);
return -EIO;
}
while (len-- > 0) {
- if (i2c_gpio_write_byte(scl, sda, delay, *buffer++))
+ if (i2c_gpio_write_byte(bus, delay, *buffer++))
failures++;
}
if (!end_with_repeated_start) {
- i2c_gpio_send_stop(scl, sda, delay);
+ i2c_gpio_send_stop(bus, delay);
return failures;
}
- if (i2c_send_slave_addr(scl, sda, delay, (chip << 1) | 0x1)) {
+ if (i2c_send_slave_addr(bus, delay, (chip << 1) | 0x1)) {
debug("i2c_write, no chip responded %02X\n", chip);
return -EIO;
}
@@ -237,16 +252,14 @@ static int i2c_gpio_write_data(struct i2c_gpio_bus *bus, uchar chip,
static int i2c_gpio_read_data(struct i2c_gpio_bus *bus, uchar chip,
uchar *buffer, int len)
{
- struct gpio_desc *scl = &bus->gpios[PIN_SCL];
- struct gpio_desc *sda = &bus->gpios[PIN_SDA];
unsigned int delay = bus->udelay;
debug("%s: chip %x buffer: %p len %d\n", __func__, chip, buffer, len);
while (len-- > 0)
- *buffer++ = i2c_gpio_read_byte(scl, sda, delay, len == 0);
+ *buffer++ = i2c_gpio_read_byte(bus, delay, len == 0);
- i2c_gpio_send_stop(scl, sda, delay);
+ i2c_gpio_send_stop(bus, delay);
return 0;
}
@@ -277,14 +290,12 @@ static int i2c_gpio_xfer(struct udevice *dev, struct i2c_msg *msg, int nmsgs)
static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags)
{
struct i2c_gpio_bus *bus = dev_get_priv(dev);
- struct gpio_desc *scl = &bus->gpios[PIN_SCL];
- struct gpio_desc *sda = &bus->gpios[PIN_SDA];
unsigned int delay = bus->udelay;
int ret;
- i2c_gpio_send_start(scl, sda, delay);
- ret = i2c_gpio_write_byte(scl, sda, delay, (chip << 1) | 0);
- i2c_gpio_send_stop(scl, sda, delay);
+ i2c_gpio_send_start(bus, delay);
+ ret = i2c_gpio_write_byte(bus, delay, (chip << 1) | 0);
+ i2c_gpio_send_stop(bus, delay);
debug("%s: bus: %d (%s) chip: %x flags: %x ret: %d\n",
__func__, dev->seq, dev->name, chip, chip_flags, ret);
@@ -295,12 +306,25 @@ static int i2c_gpio_probe(struct udevice *dev, uint chip, uint chip_flags)
static int i2c_gpio_set_bus_speed(struct udevice *dev, unsigned int speed_hz)
{
struct i2c_gpio_bus *bus = dev_get_priv(dev);
- struct gpio_desc *scl = &bus->gpios[PIN_SCL];
- struct gpio_desc *sda = &bus->gpios[PIN_SDA];
bus->udelay = 1000000 / (speed_hz << 2);
- i2c_gpio_send_reset(scl, sda, bus->udelay);
+ i2c_gpio_send_reset(bus, bus->udelay);
+
+ return 0;
+}
+
+static int i2c_gpio_drv_probe(struct udevice *dev)
+{
+ if (dev_read_bool(dev, "i2c-gpio,deblock")) {
+ /* @200kHz 9 clocks = 44us, 62us is ok */
+ const unsigned int DELAY_ABORT_SEQ = 62;
+ struct i2c_gpio_bus *bus = dev_get_priv(dev);
+
+ return i2c_deblock_gpio_loop(&bus->gpios[PIN_SDA],
+ &bus->gpios[PIN_SCL],
+ 16, 5, DELAY_ABORT_SEQ);
+ }
return 0;
}
@@ -320,6 +344,13 @@ static int i2c_gpio_ofdata_to_platdata(struct udevice *dev)
bus->udelay = fdtdec_get_int(blob, node, "i2c-gpio,delay-us",
DEFAULT_UDELAY);
+ bus->get_sda = i2c_gpio_sda_get;
+ bus->set_sda = i2c_gpio_sda_set;
+ if (fdtdec_get_bool(blob, node, "i2c-gpio,scl-output-only"))
+ bus->set_scl = i2c_gpio_scl_set_output_only;
+ else
+ bus->set_scl = i2c_gpio_scl_set;
+
return 0;
error:
pr_err("Can't get %s gpios! Error: %d", dev->name, ret);
@@ -341,6 +372,7 @@ U_BOOT_DRIVER(i2c_gpio) = {
.name = "i2c-gpio",
.id = UCLASS_I2C,
.of_match = i2c_gpio_ids,
+ .probe = i2c_gpio_drv_probe,
.ofdata_to_platdata = i2c_gpio_ofdata_to_platdata,
.priv_auto_alloc_size = sizeof(struct i2c_gpio_bus),
.ops = &i2c_gpio_ops,
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 2aa3efe8aa..e9ec388576 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -501,35 +501,53 @@ static int i2c_gpio_get_pin(struct gpio_desc *pin)
return dm_gpio_get_value(pin);
}
-static int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin,
- struct gpio_desc *scl_pin)
+int i2c_deblock_gpio_loop(struct gpio_desc *sda_pin,
+ struct gpio_desc *scl_pin,
+ unsigned int scl_count,
+ unsigned int start_count,
+ unsigned int delay)
{
- int counter = 9;
- int ret = 0;
+ int i, ret = -EREMOTEIO;
i2c_gpio_set_pin(sda_pin, 1);
i2c_gpio_set_pin(scl_pin, 1);
- udelay(5);
+ udelay(delay);
/* Toggle SCL until slave release SDA */
- while (counter-- >= 0) {
+ while (scl_count-- >= 0) {
i2c_gpio_set_pin(scl_pin, 1);
- udelay(5);
+ udelay(delay);
i2c_gpio_set_pin(scl_pin, 0);
- udelay(5);
- if (i2c_gpio_get_pin(sda_pin))
+ udelay(delay);
+ if (i2c_gpio_get_pin(sda_pin)) {
+ ret = 0;
break;
+ }
+ }
+
+ if (!ret && start_count) {
+ for (i = 0; i < start_count; i++) {
+ /* Send start condition */
+ udelay(delay);
+ i2c_gpio_set_pin(sda_pin, 1);
+ udelay(delay);
+ i2c_gpio_set_pin(scl_pin, 1);
+ udelay(delay);
+ i2c_gpio_set_pin(sda_pin, 0);
+ udelay(delay);
+ i2c_gpio_set_pin(scl_pin, 0);
+ }
}
/* Then, send I2C stop */
i2c_gpio_set_pin(sda_pin, 0);
- udelay(5);
+ udelay(delay);
i2c_gpio_set_pin(scl_pin, 1);
- udelay(5);
+ udelay(delay);
i2c_gpio_set_pin(sda_pin, 1);
- udelay(5);
+ udelay(delay);
if (!i2c_gpio_get_pin(sda_pin) || !i2c_gpio_get_pin(scl_pin))
ret = -EREMOTEIO;
@@ -561,7 +579,7 @@ static int i2c_deblock_gpio(struct udevice *bus)
goto out_no_pinctrl;
}
- ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL]);
+ ret0 = i2c_deblock_gpio_loop(&gpios[PIN_SDA], &gpios[PIN_SCL], 9, 0, 5);
ret = pinctrl_select_state(bus, "default");
if (ret) {
diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c
index 7d046c1a1e..fc5c1221e1 100644
--- a/drivers/i2c/stm32f7_i2c.c
+++ b/drivers/i2c/stm32f7_i2c.c
@@ -7,10 +7,10 @@
#include <clk.h>
#include <dm.h>
#include <i2c.h>
-#include <malloc.h>
#include <reset.h>
#include <dm/device.h>
+#include <linux/err.h>
#include <linux/io.h>
/* STM32 I2C registers */
@@ -145,7 +145,6 @@ struct stm32_i2c_spec {
/**
* struct stm32_i2c_setup - private I2C timing setup parameters
- * @speed: I2C speed mode (standard, Fast Plus)
* @speed_freq: I2C speed frequency (Hz)
* @clock_src: I2C clock source frequency (Hz)
* @rise_time: Rise time (ns)
@@ -154,7 +153,6 @@ struct stm32_i2c_spec {
* @analog_filter: Analog filter delay (On/Off)
*/
struct stm32_i2c_setup {
- enum i2c_speed_mode speed;
u32 speed_freq;
u32 clock_src;
u32 rise_time;
@@ -184,10 +182,11 @@ struct stm32_i2c_priv {
struct stm32_i2c_regs *regs;
struct clk clk;
struct stm32_i2c_setup *setup;
- int speed;
+ u32 speed;
};
static const struct stm32_i2c_spec i2c_specs[] = {
+ /* Standard speed - 100 KHz */
[IC_SPEED_MODE_STANDARD] = {
.rate = I2C_SPEED_STANDARD_RATE,
.rate_min = 8000,
@@ -200,6 +199,7 @@ static const struct stm32_i2c_spec i2c_specs[] = {
.l_min = 4700,
.h_min = 4000,
},
+ /* Fast speed - 400 KHz */
[IC_SPEED_MODE_FAST] = {
.rate = I2C_SPEED_FAST_RATE,
.rate_min = 320000,
@@ -212,6 +212,7 @@ static const struct stm32_i2c_spec i2c_specs[] = {
.l_min = 1300,
.h_min = 600,
},
+ /* Fast Plus Speed - 1 MHz */
[IC_SPEED_MODE_FAST_PLUS] = {
.rate = I2C_SPEED_FAST_PLUS_RATE,
.rate_min = 800000,
@@ -474,6 +475,7 @@ static int stm32_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
}
static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
+ const struct stm32_i2c_spec *specs,
struct list_head *solutions)
{
struct stm32_i2c_timings *v;
@@ -490,13 +492,13 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
af_delay_max = setup->analog_filter ?
STM32_I2C_ANALOG_FILTER_DELAY_MAX : 0;
- sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time -
+ sdadel_min = specs->hddat_min + setup->fall_time -
af_delay_min - (setup->dnf + 3) * i2cclk;
- sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time -
+ sdadel_max = specs->vddat_max - setup->rise_time -
af_delay_max - (setup->dnf + 4) * i2cclk;
- scldel_min = setup->rise_time + i2c_specs[setup->speed].sudat_min;
+ scldel_min = setup->rise_time + specs->sudat_min;
if (sdadel_min < 0)
sdadel_min = 0;
@@ -548,6 +550,7 @@ static int stm32_i2c_compute_solutions(struct stm32_i2c_setup *setup,
}
static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
+ const struct stm32_i2c_spec *specs,
struct list_head *solutions,
struct stm32_i2c_timings *s)
{
@@ -570,8 +573,8 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
dnf_delay = setup->dnf * i2cclk;
tsync = af_delay_min + dnf_delay + (2 * i2cclk);
- clk_max = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_min;
- clk_min = STM32_NSEC_PER_SEC / i2c_specs[setup->speed].rate_max;
+ clk_max = STM32_NSEC_PER_SEC / specs->rate_min;
+ clk_min = STM32_NSEC_PER_SEC / specs->rate_max;
/*
* Among Prescaler possibilities discovered above figures out SCL Low
@@ -589,7 +592,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
for (l = 0; l < STM32_SCLL_MAX; l++) {
u32 tscl_l = (l + 1) * prescaler + tsync;
- if ((tscl_l < i2c_specs[setup->speed].l_min) ||
+ if (tscl_l < specs->l_min ||
(i2cclk >=
((tscl_l - af_delay_min - dnf_delay) / 4))) {
continue;
@@ -601,7 +604,7 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
setup->rise_time + setup->fall_time;
if ((tscl >= clk_min) && (tscl <= clk_max) &&
- (tscl_h >= i2c_specs[setup->speed].h_min) &&
+ (tscl_h >= specs->h_min) &&
(i2cclk < tscl_h)) {
u32 clk_error;
@@ -630,26 +633,40 @@ static int stm32_i2c_choose_solution(struct stm32_i2c_setup *setup,
return ret;
}
+static const struct stm32_i2c_spec *get_specs(u32 rate)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(i2c_specs); i++)
+ if (rate <= i2c_specs[i].rate)
+ return &i2c_specs[i];
+
+ /* NOT REACHED */
+ return ERR_PTR(-EINVAL);
+}
+
static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv,
struct stm32_i2c_setup *setup,
struct stm32_i2c_timings *output)
{
+ const struct stm32_i2c_spec *specs;
struct stm32_i2c_timings *v, *_v;
struct list_head solutions;
int ret;
- if (setup->speed >= ARRAY_SIZE(i2c_specs)) {
- pr_err("%s: speed out of bound {%d/%d}\n", __func__,
- setup->speed, ARRAY_SIZE(i2c_specs) - 1);
+ specs = get_specs(setup->speed_freq);
+ if (specs == ERR_PTR(-EINVAL)) {
+ pr_err("%s: speed out of bound {%d}\n", __func__,
+ setup->speed_freq);
return -EINVAL;
}
- if ((setup->rise_time > i2c_specs[setup->speed].rise_max) ||
- (setup->fall_time > i2c_specs[setup->speed].fall_max)) {
+ if (setup->rise_time > specs->rise_max ||
+ setup->fall_time > specs->fall_max) {
pr_err("%s :timings out of bound Rise{%d>%d}/Fall{%d>%d}\n",
__func__,
- setup->rise_time, i2c_specs[setup->speed].rise_max,
- setup->fall_time, i2c_specs[setup->speed].fall_max);
+ setup->rise_time, specs->rise_max,
+ setup->fall_time, specs->fall_max);
return -EINVAL;
}
@@ -659,18 +676,12 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv,
return -EINVAL;
}
- if (setup->speed_freq > i2c_specs[setup->speed].rate) {
- pr_err("%s: Freq {%d/%d}\n", __func__,
- setup->speed_freq, i2c_specs[setup->speed].rate);
- return -EINVAL;
- }
-
INIT_LIST_HEAD(&solutions);
- ret = stm32_i2c_compute_solutions(setup, &solutions);
+ ret = stm32_i2c_compute_solutions(setup, specs, &solutions);
if (ret)
goto exit;
- ret = stm32_i2c_choose_solution(setup, &solutions, output);
+ ret = stm32_i2c_choose_solution(setup, specs, &solutions, output);
if (ret)
goto exit;
@@ -689,14 +700,24 @@ exit:
return ret;
}
+static u32 get_lower_rate(u32 rate)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(i2c_specs) - 1; i >= 0; i--)
+ if (rate > i2c_specs[i].rate)
+ return i2c_specs[i].rate;
+
+ return i2c_specs[0].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;
int ret = 0;
- setup->speed = i2c_priv->speed;
- setup->speed_freq = i2c_specs[setup->speed].rate;
+ setup->speed_freq = i2c_priv->speed;
setup->clock_src = clk_get_rate(&i2c_priv->clk);
if (!setup->clock_src) {
@@ -709,13 +730,11 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
if (ret) {
debug("%s: failed to compute I2C timings.\n",
__func__);
- if (i2c_priv->speed > IC_SPEED_MODE_STANDARD) {
- i2c_priv->speed--;
- setup->speed = i2c_priv->speed;
+ if (setup->speed_freq > I2C_SPEED_STANDARD_RATE) {
setup->speed_freq =
- i2c_specs[setup->speed].rate;
+ get_lower_rate(setup->speed_freq);
debug("%s: downgrade I2C Speed Freq to (%i)\n",
- __func__, i2c_specs[setup->speed].rate);
+ __func__, setup->speed_freq);
} else {
break;
}
@@ -727,13 +746,15 @@ static int stm32_i2c_setup_timing(struct stm32_i2c_priv *i2c_priv,
return ret;
}
- debug("%s: I2C Speed(%i), Freq(%i), Clk Source(%i)\n", __func__,
- setup->speed, setup->speed_freq, setup->clock_src);
+ debug("%s: I2C Freq(%i), Clk Source(%i)\n", __func__,
+ setup->speed_freq, setup->clock_src);
debug("%s: I2C Rise(%i) and Fall(%i) Time\n", __func__,
setup->rise_time, setup->fall_time);
debug("%s: I2C Analog Filter(%s), DNF(%i)\n", __func__,
setup->analog_filter ? "On" : "Off", setup->dnf);
+ i2c_priv->speed = setup->speed_freq;
+
return 0;
}
@@ -773,21 +794,13 @@ static int stm32_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
{
struct stm32_i2c_priv *i2c_priv = dev_get_priv(bus);
- switch (speed) {
- case I2C_SPEED_STANDARD_RATE:
- i2c_priv->speed = IC_SPEED_MODE_STANDARD;
- break;
- case I2C_SPEED_FAST_RATE:
- i2c_priv->speed = IC_SPEED_MODE_FAST;
- break;
- case I2C_SPEED_FAST_PLUS_RATE:
- i2c_priv->speed = IC_SPEED_MODE_FAST_PLUS;
- break;
- default:
+ if (speed > I2C_SPEED_FAST_PLUS_RATE) {
debug("%s: Speed %d not supported\n", __func__, speed);
return -EINVAL;
}
+ i2c_priv->speed = speed;
+
return stm32_i2c_hw_config(i2c_priv);
}
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index f18aa8f7ba..766402745d 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -462,6 +462,11 @@ config IHS_FPGA
gdsys devices, which supply the majority of the functionality offered
by the devices. This driver supports both CON and CPU variants of the
devices, depending on the device tree entry.
+config ESM_K3
+ bool "Enable K3 ESM driver"
+ depends on ARCH_K3
+ help
+ Support ESM (Error Signaling Module) on TI K3 SoCs.
config MICROCHIP_FLEXCOM
bool "Enable Microchip Flexcom driver"
@@ -481,4 +486,11 @@ config K3_AVS0
optimized voltage from the efuse, so that it can be programmed
to the PMIC on board.
+config ESM_PMIC
+ bool "Enable PMIC ESM driver"
+ depends on DM_PMIC
+ help
+ Support ESM (Error Signal Monitor) on PMIC devices. ESM is used
+ typically to reboot the board in error condition.
+
endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 2b843de93c..68e0e7ad17 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -72,3 +72,5 @@ obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
obj-$(CONFIG_JZ4780_EFUSE) += jz4780_efuse.o
obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o
obj-$(CONFIG_K3_AVS0) += k3_avs.o
+obj-$(CONFIG_ESM_K3) += k3_esm.o
+obj-$(CONFIG_ESM_PMIC) += esm_pmic.o
diff --git a/drivers/misc/esm_pmic.c b/drivers/misc/esm_pmic.c
new file mode 100644
index 0000000000..92c8d68f7c
--- /dev/null
+++ b/drivers/misc/esm_pmic.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * PMIC Error Signal Monitor driver
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <power/pmic.h>
+#include <dm/device_compat.h>
+
+#define INT_ESM_REG 0x6c
+#define INT_ESM_MASK 0x3f
+
+#define ESM_MCU_START_REG 0x8f
+
+#define ESM_MCU_START BIT(0)
+
+#define ESM_MCU_MODE_CFG_REG 0x92
+
+#define ESM_MCU_EN BIT(6)
+#define ESM_MCU_ENDRV BIT(5)
+
+/**
+ * pmic_esm_probe: configures and enables PMIC ESM functionality
+ *
+ * Configures ESM PMIC support and enables it.
+ */
+static int pmic_esm_probe(struct udevice *dev)
+{
+ int ret;
+
+ ret = pmic_reg_write(dev->parent, INT_ESM_REG, INT_ESM_MASK);
+ if (ret) {
+ dev_err(dev, "clearing ESM irqs failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = pmic_reg_write(dev->parent, ESM_MCU_MODE_CFG_REG,
+ ESM_MCU_EN | ESM_MCU_ENDRV);
+ if (ret) {
+ dev_err(dev, "setting ESM mode failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = pmic_reg_write(dev->parent, ESM_MCU_START_REG, ESM_MCU_START);
+ if (ret) {
+ dev_err(dev, "starting ESM failed: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct udevice_id pmic_esm_ids[] = {
+ { .compatible = "ti,tps659413-esm" },
+ {}
+};
+
+U_BOOT_DRIVER(pmic_esm) = {
+ .name = "esm_pmic",
+ .of_match = pmic_esm_ids,
+ .id = UCLASS_MISC,
+ .probe = pmic_esm_probe,
+};
diff --git a/drivers/misc/i2c_eeprom.c b/drivers/misc/i2c_eeprom.c
index 6c0459dc55..ef5f103c98 100644
--- a/drivers/misc/i2c_eeprom.c
+++ b/drivers/misc/i2c_eeprom.c
@@ -14,7 +14,7 @@
struct i2c_eeprom_drv_data {
u32 size; /* size in bytes */
- u32 pagewidth; /* pagesize = 2^pagewidth */
+ u32 pagesize; /* page size in bytes */
u32 addr_offset_mask; /* bits in addr used for offset overflow */
u32 offset_len; /* size in bytes of offset */
};
@@ -99,13 +99,11 @@ static int i2c_eeprom_std_ofdata_to_platdata(struct udevice *dev)
u32 pagesize;
u32 size;
- if (dev_read_u32(dev, "pagesize", &pagesize) == 0) {
+ if (dev_read_u32(dev, "pagesize", &pagesize) == 0)
priv->pagesize = pagesize;
- } else {
+ else
/* 6 bit -> page size of up to 2^63 (should be sufficient) */
- priv->pagewidth = data->pagewidth;
- priv->pagesize = (1 << priv->pagewidth);
- }
+ priv->pagesize = data->pagesize;
if (dev_read_u32(dev, "size", &size) == 0)
priv->size = size;
@@ -158,98 +156,98 @@ static int i2c_eeprom_std_probe(struct udevice *dev)
static const struct i2c_eeprom_drv_data eeprom_data = {
.size = 0,
- .pagewidth = 0,
+ .pagesize = 1,
.addr_offset_mask = 0,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data mc24aa02e48_data = {
.size = 256,
- .pagewidth = 3,
+ .pagesize = 8,
.addr_offset_mask = 0,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c01a_data = {
.size = 128,
- .pagewidth = 3,
+ .pagesize = 8,
.addr_offset_mask = 0,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c02_data = {
.size = 256,
- .pagewidth = 3,
+ .pagesize = 8,
.addr_offset_mask = 0,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c04_data = {
.size = 512,
- .pagewidth = 4,
+ .pagesize = 16,
.addr_offset_mask = 0x1,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c08_data = {
.size = 1024,
- .pagewidth = 4,
+ .pagesize = 16,
.addr_offset_mask = 0x3,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c08a_data = {
.size = 1024,
- .pagewidth = 4,
+ .pagesize = 16,
.addr_offset_mask = 0x3,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c16a_data = {
.size = 2048,
- .pagewidth = 4,
+ .pagesize = 16,
.addr_offset_mask = 0x7,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24mac402_data = {
.size = 256,
- .pagewidth = 4,
+ .pagesize = 16,
.addr_offset_mask = 0,
.offset_len = 1,
};
static const struct i2c_eeprom_drv_data atmel24c32_data = {
.size = 4096,
- .pagewidth = 5,
+ .pagesize = 32,
.addr_offset_mask = 0,
.offset_len = 2,
};
static const struct i2c_eeprom_drv_data atmel24c64_data = {
.size = 8192,
- .pagewidth = 5,
+ .pagesize = 32,
.addr_offset_mask = 0,
.offset_len = 2,
};
static const struct i2c_eeprom_drv_data atmel24c128_data = {
.size = 16384,
- .pagewidth = 6,
+ .pagesize = 64,
.addr_offset_mask = 0,
.offset_len = 2,
};
static const struct i2c_eeprom_drv_data atmel24c256_data = {
.size = 32768,
- .pagewidth = 6,
+ .pagesize = 64,
.addr_offset_mask = 0,
.offset_len = 2,
};
static const struct i2c_eeprom_drv_data atmel24c512_data = {
.size = 65536,
- .pagewidth = 6,
+ .pagesize = 64,
.addr_offset_mask = 0,
.offset_len = 2,
};
diff --git a/drivers/misc/k3_avs.c b/drivers/misc/k3_avs.c
index 90df377250..d8048e1b70 100644
--- a/drivers/misc/k3_avs.c
+++ b/drivers/misc/k3_avs.c
@@ -316,15 +316,15 @@ static struct vd_data am654_vd_data[] = {
.opp = AM6_OPP_NOM,
.opps = {
[AM6_OPP_NOM] = {
- .volt = 1000000,
+ .volt = 1100000,
.freq = 800000000,
},
[AM6_OPP_OD] = {
- .volt = 1100000,
+ .volt = 1200000,
.freq = 1000000000,
},
[AM6_OPP_TURBO] = {
- .volt = 1220000,
+ .volt = 1240000,
.freq = 1100000000,
},
},
@@ -336,15 +336,15 @@ static struct vd_data am654_vd_data[] = {
.clk_id = 0, /* ARM clock */
.opps = {
[AM6_OPP_NOM] = {
- .volt = 1000000,
+ .volt = 1100000,
.freq = 800000000,
},
[AM6_OPP_OD] = {
- .volt = 1100000,
+ .volt = 1200000,
.freq = 1000000000,
},
[AM6_OPP_TURBO] = {
- .volt = 1220000,
+ .volt = 1240000,
.freq = 1100000000,
},
},
diff --git a/drivers/misc/k3_esm.c b/drivers/misc/k3_esm.c
new file mode 100644
index 0000000000..8f270f3b5c
--- /dev/null
+++ b/drivers/misc/k3_esm.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Texas Instruments' K3 Error Signalling Module driver
+ *
+ * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <dm/device_compat.h>
+
+#define ESM_SFT_RST 0x0c
+#define ESM_SFT_RST_KEY 0x0f
+
+#define ESM_STS(i) (0x404 + (i) / 32 * 0x20)
+#define ESM_PIN_EN_SET_OFFSET(i) (0x414 + (i) / 32 * 0x20)
+#define ESM_PIN_MASK(i) BIT((i) & 0x1f)
+
+static void esm_pin_enable(void __iomem *base, int pin)
+{
+ /* Enable event */
+ writel(ESM_PIN_MASK(pin), base + ESM_PIN_EN_SET_OFFSET(pin));
+}
+
+/**
+ * k3_esm_probe: configures ESM based on DT data
+ *
+ * Parses ESM info from device tree, and configures the module accordingly.
+ */
+static int k3_esm_probe(struct udevice *dev)
+{
+ int ret;
+ void __iomem *base;
+ int num_pins;
+ u32 *pins;
+ int i;
+
+ base = dev_remap_addr_index(dev, 0);
+ if (!base)
+ return -ENODEV;
+
+ num_pins = dev_read_size(dev, "ti,esm-pins");
+ if (num_pins < 0) {
+ dev_err(dev, "ti,esm-pins property missing or invalid: %d\n",
+ num_pins);
+ return num_pins;
+ }
+
+ num_pins /= sizeof(u32);
+
+ pins = kmalloc(num_pins * sizeof(u32), __GFP_ZERO);
+ if (!pins)
+ return -ENOMEM;
+
+ ret = dev_read_u32_array(dev, "ti,esm-pins", pins, num_pins);
+ if (ret < 0) {
+ dev_err(dev, "failed to read ti,esm-pins property: %d\n",
+ ret);
+ goto free_pins;
+ }
+
+ /* Clear any pending events */
+ writel(ESM_SFT_RST_KEY, base + ESM_SFT_RST);
+
+ for (i = 0; i < num_pins; i++)
+ esm_pin_enable(base, pins[i]);
+
+free_pins:
+ kfree(pins);
+ return ret;
+}
+
+static const struct udevice_id k3_esm_ids[] = {
+ { .compatible = "ti,j721e-esm" },
+ {}
+};
+
+U_BOOT_DRIVER(k3_esm) = {
+ .name = "k3_esm",
+ .of_match = k3_esm_ids,
+ .id = UCLASS_MISC,
+ .probe = k3_esm_probe,
+};
diff --git a/drivers/mmc/meson_gx_mmc.c b/drivers/mmc/meson_gx_mmc.c
index b5f5122b1b..86c1a7164a 100644
--- a/drivers/mmc/meson_gx_mmc.c
+++ b/drivers/mmc/meson_gx_mmc.c
@@ -4,6 +4,7 @@
*/
#include <common.h>
+#include <clk.h>
#include <cpu_func.h>
#include <dm.h>
#include <fdtdec.h>
@@ -241,12 +242,23 @@ static int meson_mmc_probe(struct udevice *dev)
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
struct mmc *mmc = &pdata->mmc;
struct mmc_config *cfg = &pdata->cfg;
+ struct clk_bulk clocks;
uint32_t val;
+ int ret;
+
#ifdef CONFIG_PWRSEQ
struct udevice *pwr_dev;
- int ret;
#endif
+ /* Enable the clocks feeding the MMC controller */
+ ret = clk_get_bulk(dev, &clocks);
+ if (ret)
+ return ret;
+
+ ret = clk_enable_bulk(&clocks);
+ if (ret)
+ return ret;
+
cfg->voltages = MMC_VDD_33_34 | MMC_VDD_32_33 |
MMC_VDD_31_32 | MMC_VDD_165_195;
cfg->host_caps = MMC_MODE_8BIT | MMC_MODE_4BIT |
diff --git a/drivers/mtd/nand/raw/zynq_nand.c b/drivers/mtd/nand/raw/zynq_nand.c
index 28db4153f5..0aea83dac0 100644
--- a/drivers/mtd/nand/raw/zynq_nand.c
+++ b/drivers/mtd/nand/raw/zynq_nand.c
@@ -1081,18 +1081,23 @@ static int zynq_nand_probe(struct udevice *dev)
u8 set_feature[4] = {ONDIE_ECC_FEATURE_ENABLE, 0x00, 0x00, 0x00};
unsigned long ecc_cfg;
int ondie_ecc_enabled = 0;
- int err = -1;
int is_16bit_bw;
smc->reg = (struct zynq_nand_smc_regs *)dev_read_addr(dev);
of_nand = dev_read_subnode(dev, "flash@e1000000");
if (!ofnode_valid(of_nand)) {
printf("Failed to find nand node in dt\n");
- goto fail;
+ return -ENODEV;
}
+
+ if (!ofnode_is_available(of_nand)) {
+ debug("Nand node in dt disabled\n");
+ return dm_scan_fdt_dev(dev);
+ }
+
if (ofnode_read_resource(of_nand, 0, &res)) {
printf("Failed to get nand resource\n");
- goto fail;
+ return -ENODEV;
}
xnand->nand_base = (void __iomem *)res.start;
@@ -1119,7 +1124,7 @@ static int zynq_nand_probe(struct udevice *dev)
if (is_16bit_bw == NAND_BW_UNKNOWN) {
printf("%s: Unable detect NAND based on MIO settings\n",
__func__);
- goto fail;
+ return -EINVAL;
}
if (is_16bit_bw == NAND_BW_16BIT)
@@ -1130,13 +1135,13 @@ static int zynq_nand_probe(struct udevice *dev)
/* Initialize the NAND flash interface on NAND controller */
if (zynq_nand_init_nand_flash(mtd, nand_chip->options) < 0) {
printf("%s: nand flash init failed\n", __func__);
- goto fail;
+ return -EINVAL;
}
/* first scan to find the device and get the page size */
if (nand_scan_ident(mtd, 1, NULL)) {
printf("%s: nand_scan_ident failed\n", __func__);
- goto fail;
+ return -EINVAL;
}
/* Send the command for reading device ID */
nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
@@ -1261,14 +1266,12 @@ static int zynq_nand_probe(struct udevice *dev)
/* Second phase scan */
if (nand_scan_tail(mtd)) {
printf("%s: nand_scan_tail failed\n", __func__);
- goto fail;
+ return -EINVAL;
}
if (nand_register(0, mtd))
- goto fail;
+ return -EINVAL;
+
return 0;
-fail:
- free(xnand);
- return err;
}
static const struct udevice_id zynq_nand_dt_ids[] = {
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 5f2f87d352..a158824fc9 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -197,6 +197,7 @@ struct zynq_gem_priv {
int phyaddr;
int init;
struct zynq_gem_regs *iobase;
+ struct zynq_gem_regs *mdiobase;
phy_interface_t interface;
struct phy_device *phydev;
ofnode phy_of_node;
@@ -211,7 +212,7 @@ static int phy_setup_op(struct zynq_gem_priv *priv, u32 phy_addr, u32 regnum,
u32 op, u16 *data)
{
u32 mgtcr;
- struct zynq_gem_regs *regs = priv->iobase;
+ struct zynq_gem_regs *regs = priv->mdiobase;
int err;
err = wait_for_bit_le32(&regs->nwsr, ZYNQ_GEM_NWSR_MDIOIDLE_MASK,
@@ -297,7 +298,7 @@ static int zynq_phy_init(struct udevice *dev)
{
int ret;
struct zynq_gem_priv *priv = dev_get_priv(dev);
- struct zynq_gem_regs *regs = priv->iobase;
+ struct zynq_gem_regs *regs_mdio = priv->mdiobase;
const u32 supported = SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
@@ -306,7 +307,7 @@ static int zynq_phy_init(struct udevice *dev)
SUPPORTED_1000baseT_Full;
/* Enable only MDIO bus */
- writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, &regs->nwctrl);
+ writel(ZYNQ_GEM_NWCTRL_MDEN_MASK, &regs_mdio->nwctrl);
priv->phydev = phy_connect(priv->bus, priv->phyaddr, dev,
priv->interface);
@@ -335,6 +336,7 @@ static int zynq_gem_init(struct udevice *dev)
unsigned long clk_rate = 0;
struct zynq_gem_priv *priv = dev_get_priv(dev);
struct zynq_gem_regs *regs = priv->iobase;
+ struct zynq_gem_regs *regs_mdio = priv->mdiobase;
struct emac_bd *dummy_tx_bd = &priv->tx_bd[TX_FREE_DESC];
struct emac_bd *dummy_rx_bd = &priv->tx_bd[TX_FREE_DESC + 2];
@@ -402,7 +404,7 @@ static int zynq_gem_init(struct udevice *dev)
writel(ZYNQ_GEM_DMACR_INIT, &regs->dmacr);
/* Setup for Network Control register, MDIO, Rx and Tx enable */
- setbits_le32(&regs->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK);
+ setbits_le32(&regs_mdio->nwctrl, ZYNQ_GEM_NWCTRL_MDEN_MASK);
/* Disable the second priority queue */
dummy_tx_bd->addr = 0;
@@ -578,6 +580,7 @@ static int zynq_gem_free_pkt(struct udevice *dev, uchar *packet, int length)
struct zynq_gem_priv *priv = dev_get_priv(dev);
struct emac_bd *current_bd = &priv->rx_bd[priv->rxbd_current];
struct emac_bd *first_bd;
+ dma_addr_t addr;
if (current_bd->status & ZYNQ_GEM_RXBUF_SOF_MASK) {
priv->rx_first_buf = priv->rxbd_current;
@@ -592,6 +595,17 @@ static int zynq_gem_free_pkt(struct udevice *dev, uchar *packet, int length)
first_bd->status = 0xF0000000;
}
+ /* Flush the cache for the packet as well */
+#if defined(CONFIG_PHYS_64BIT)
+ addr = (dma_addr_t)((current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK)
+ | ((dma_addr_t)current_bd->addr_hi << 32));
+#else
+ addr = current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK;
+#endif
+ flush_dcache_range(addr, addr + roundup(PKTSIZE_ALIGN,
+ ARCH_DMA_MINALIGN));
+ barrier();
+
if ((++priv->rxbd_current) >= RX_BUF)
priv->rxbd_current = 0;
@@ -731,6 +745,7 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev)
pdata->iobase = (phys_addr_t)dev_read_addr(dev);
priv->iobase = (struct zynq_gem_regs *)pdata->iobase;
+ priv->mdiobase = priv->iobase;
/* Hardcode for now */
priv->phyaddr = -1;
@@ -756,8 +771,9 @@ static int zynq_gem_ofdata_to_platdata(struct udevice *dev)
priv->int_pcs = dev_read_bool(dev, "is-internal-pcspma");
- printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv->iobase,
- priv->phyaddr, phy_string_for_interface(priv->interface));
+ printf("\nZYNQ GEM: %lx, mdio bus %lx, phyaddr %d, interface %s\n",
+ (ulong)priv->iobase, (ulong)priv->mdiobase, priv->phyaddr,
+ phy_string_for_interface(priv->interface));
return 0;
}
diff --git a/drivers/power/pmic/tps65941.c b/drivers/power/pmic/tps65941.c
index e8f3c950bd..7b3416ae6e 100644
--- a/drivers/power/pmic/tps65941.c
+++ b/drivers/power/pmic/tps65941.c
@@ -59,8 +59,8 @@ static int tps65941_bind(struct udevice *dev)
if (!children)
printf("%s: %s - no child found\n", __func__, dev->name);
- /* Always return success for this device */
- return 0;
+ /* Probe all the child devices */
+ return dm_scan_fdt_dev(dev);
}
static struct dm_pmic_ops tps65941_ops = {
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.c b/drivers/ram/stm32mp1/stm32mp1_ddr.c
index d765a46f7c..11b14ae652 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.c
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.c
@@ -639,7 +639,8 @@ void stm32mp1_refresh_disable(struct stm32mp1_ddrctl *ctl)
start_sw_done(ctl);
/* quasi-dynamic register update*/
setbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
- clrbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
+ clrbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN |
+ DDRCTRL_PWRCTL_SELFREF_EN);
clrbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
wait_sw_done_ack(ctl);
}
@@ -652,6 +653,8 @@ void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl,
clrbits_le32(&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH);
if (pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN)
setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN);
+ if ((pwrctl & DDRCTRL_PWRCTL_SELFREF_EN))
+ setbits_le32(&ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_EN);
setbits_le32(&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN);
wait_sw_done_ack(ctl);
}
@@ -668,14 +671,34 @@ void stm32mp1_ddr_init(struct ddr_info *priv,
{
u32 pir;
int ret = -EINVAL;
+ char bus_width;
+
+ switch (config->c_reg.mstr & DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK) {
+ case DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER:
+ bus_width = 8;
+ break;
+ case DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF:
+ bus_width = 16;
+ break;
+ default:
+ bus_width = 32;
+ break;
+ }
+
if (config->c_reg.mstr & DDRCTRL_MSTR_DDR3)
ret = board_ddr_power_init(STM32MP_DDR3);
- else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2)
- ret = board_ddr_power_init(STM32MP_LPDDR2);
- else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3)
- ret = board_ddr_power_init(STM32MP_LPDDR3);
-
+ else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR2) {
+ if (bus_width == 32)
+ ret = board_ddr_power_init(STM32MP_LPDDR2_32);
+ else
+ ret = board_ddr_power_init(STM32MP_LPDDR2_16);
+ } else if (config->c_reg.mstr & DDRCTRL_MSTR_LPDDR3) {
+ if (bus_width == 32)
+ ret = board_ddr_power_init(STM32MP_LPDDR3_32);
+ else
+ ret = board_ddr_power_init(STM32MP_LPDDR3_16);
+ }
if (ret)
panic("ddr power init failed\n");
@@ -746,7 +769,8 @@ start:
*/
set_reg(priv, REGPHY_REG, &config->p_reg);
set_reg(priv, REGPHY_TIMING, &config->p_timing);
- set_reg(priv, REGPHY_CAL, &config->p_cal);
+ if (config->p_cal_present)
+ set_reg(priv, REGPHY_CAL, &config->p_cal);
if (INTERACTIVE(STEP_PHY_INIT))
goto start;
@@ -781,13 +805,16 @@ start:
wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL);
- debug("DDR DQS training : ");
+ if (config->p_cal_present) {
+ debug("DDR DQS training skipped.\n");
+ } else {
+ debug("DDR DQS training : ");
/* 8. Disable Auto refresh and power down by setting
* - RFSHCTL3.dis_au_refresh = 1
* - PWRCTL.powerdown_en = 0
* - DFIMISC.dfiinit_complete_en = 0
*/
- stm32mp1_refresh_disable(priv->ctl);
+ stm32mp1_refresh_disable(priv->ctl);
/* 9. Program PUBL PGCR to enable refresh during training and rank to train
* not done => keep the programed value in PGCR
@@ -795,14 +822,15 @@ start:
/* 10. configure PUBL PIR register to specify which training step to run */
/* warning : RVTRN is not supported by this PUBL */
- stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
+ stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN);
/* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */
- ddrphy_idone_wait(priv->phy);
+ ddrphy_idone_wait(priv->phy);
/* 12. set back registers in step 8 to the orginal values if desidered */
- stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
- config->c_reg.pwrctl);
+ stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3,
+ config->c_reg.pwrctl);
+ } /* if (config->p_cal_present) */
/* enable uMCTL2 AXI port 0 and 1 */
setbits_le32(&priv->ctl->pctrl_0, DDRCTRL_PCTRL_N_PORT_EN);
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr.h b/drivers/ram/stm32mp1/stm32mp1_ddr.h
index 52b748f3ca..4998f04439 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr.h
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr.h
@@ -170,6 +170,7 @@ struct stm32mp1_ddr_config {
struct stm32mp1_ddrphy_reg p_reg;
struct stm32mp1_ddrphy_timing p_timing;
struct stm32mp1_ddrphy_cal p_cal;
+ bool p_cal_present;
};
int stm32mp1_ddr_clk_enable(struct ddr_info *priv, u32 mem_speed);
diff --git a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
index 9d33186b3a..afd93c518e 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
+++ b/drivers/ram/stm32mp1/stm32mp1_ddr_regs.h
@@ -260,6 +260,7 @@ struct stm32mp1_ddrphy {
#define DDRCTRL_MRSTAT_MR_WR_BUSY BIT(0)
+#define DDRCTRL_PWRCTL_SELFREF_EN BIT(0)
#define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1)
#define DDRCTRL_PWRCTL_SELFREF_SW BIT(5)
diff --git a/drivers/ram/stm32mp1/stm32mp1_interactive.c b/drivers/ram/stm32mp1/stm32mp1_interactive.c
index cc9b2e7c96..805c9ddaad 100644
--- a/drivers/ram/stm32mp1/stm32mp1_interactive.c
+++ b/drivers/ram/stm32mp1/stm32mp1_interactive.c
@@ -106,7 +106,7 @@ static void stm32mp1_do_usage(void)
"help displays help\n"
"info displays DDR information\n"
"info <param> <val> changes DDR information\n"
- " with <param> = step, name, size or speed\n"
+ " with <param> = step, name, size, speed or cal\n"
"freq displays the DDR PHY frequency in kHz\n"
"freq <freq> changes the DDR PHY frequency\n"
"param [type|reg] prints input parameters\n"
@@ -160,6 +160,7 @@ static void stm32mp1_do_info(struct ddr_info *priv,
printf("name = %s\n", config->info.name);
printf("size = 0x%x\n", config->info.size);
printf("speed = %d kHz\n", config->info.speed);
+ printf("cal = %d\n", config->p_cal_present);
return;
}
@@ -208,6 +209,16 @@ static void stm32mp1_do_info(struct ddr_info *priv,
}
return;
}
+ if (!strcmp(argv[1], "cal")) {
+ if (strict_strtoul(argv[2], 10, &value) < 0 ||
+ (value != 0 && value != 1)) {
+ printf("invalid value %s\n", argv[2]);
+ } else {
+ config->p_cal_present = value;
+ printf("cal = %d\n", config->p_cal_present);
+ }
+ return;
+ }
printf("argument %s invalid\n", argv[1]);
}
@@ -367,7 +378,6 @@ bool stm32mp1_ddr_interactive(void *priv,
enum stm32mp1_ddr_interact_step step,
const struct stm32mp1_ddr_config *config)
{
- const char *prompt = "DDR>";
char buffer[CONFIG_SYS_CBSIZE];
char *argv[CONFIG_SYS_MAXARGS + 1]; /* NULL terminated */
int argc;
@@ -403,13 +413,12 @@ bool stm32mp1_ddr_interactive(void *priv,
}
printf("%d:%s\n", step, step_str[step]);
- printf("%s\n", prompt);
if (next_step > step)
return false;
while (next_step == step) {
- cli_readline_into_buffer(prompt, buffer, 0);
+ cli_readline_into_buffer("DDR>", buffer, 0);
argc = cli_simple_parse_line(buffer, argv);
if (!argc)
continue;
diff --git a/drivers/ram/stm32mp1/stm32mp1_ram.c b/drivers/ram/stm32mp1/stm32mp1_ram.c
index eb78f1198d..b1e593f86b 100644
--- a/drivers/ram/stm32mp1/stm32mp1_ram.c
+++ b/drivers/ram/stm32mp1/stm32mp1_ram.c
@@ -65,18 +65,22 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
struct clk axidcg;
struct stm32mp1_ddr_config config;
-#define PARAM(x, y) \
- { x,\
- offsetof(struct stm32mp1_ddr_config, y),\
- sizeof(config.y) / sizeof(u32)}
+#define PARAM(x, y, z) \
+ { .name = x, \
+ .offset = offsetof(struct stm32mp1_ddr_config, y), \
+ .size = sizeof(config.y) / sizeof(u32), \
+ .present = z, \
+ }
-#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x)
-#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x)
+#define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x, NULL)
+#define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x, NULL)
+#define PHY_PARAM_OPT(x) PARAM("st,phy-"#x, p_##x, &config.p_##x##_present)
const struct {
const char *name; /* name in DT */
const u32 offset; /* offset in config struct */
const u32 size; /* size of parameters */
+ bool * const present; /* presence indication for opt */
} param[] = {
CTL_PARAM(reg),
CTL_PARAM(timing),
@@ -84,7 +88,7 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
CTL_PARAM(perf),
PHY_PARAM(reg),
PHY_PARAM(timing),
- PHY_PARAM(cal)
+ PHY_PARAM_OPT(cal)
};
config.info.speed = dev_read_u32_default(dev, "st,mem-speed", 0);
@@ -103,11 +107,25 @@ static __maybe_unused int stm32mp1_ddr_setup(struct udevice *dev)
param[idx].size);
debug("%s: %s[0x%x] = %d\n", __func__,
param[idx].name, param[idx].size, ret);
- if (ret) {
+ if (ret &&
+ (ret != -FDT_ERR_NOTFOUND || !param[idx].present)) {
pr_err("%s: Cannot read %s, error=%d\n",
__func__, param[idx].name, ret);
return -EINVAL;
}
+ if (param[idx].present) {
+ /* save presence of optional parameters */
+ *param[idx].present = true;
+ if (ret == -FDT_ERR_NOTFOUND) {
+ *param[idx].present = false;
+#ifdef CONFIG_STM32MP1_DDR_INTERACTIVE
+ /* reset values if used later */
+ memset((void *)((u32)&config +
+ param[idx].offset),
+ 0, param[idx].size * sizeof(u32));
+#endif
+ }
+ }
}
ret = clk_get_by_name(dev, "axidcg", &axidcg);
diff --git a/drivers/ram/stm32mp1/stm32mp1_tuning.c b/drivers/ram/stm32mp1/stm32mp1_tuning.c
index 4e1c1fab54..3013b7b667 100644
--- a/drivers/ram/stm32mp1/stm32mp1_tuning.c
+++ b/drivers/ram/stm32mp1/stm32mp1_tuning.c
@@ -8,6 +8,8 @@
#include <ram.h>
#include <reset.h>
#include <asm/io.h>
+#include <linux/bitops.h>
+#include <linux/iopoll.h>
#include "stm32mp1_ddr_regs.h"
#include "stm32mp1_ddr.h"
@@ -75,6 +77,133 @@ static u8 get_nb_bytes(struct stm32mp1_ddrctl *ctl)
return nb_bytes;
}
+static u8 get_nb_bank(struct stm32mp1_ddrctl *ctl)
+{
+ /* Count bank address bits */
+ u8 bits = 0;
+ u32 reg, val;
+
+ reg = readl(&ctl->addrmap1);
+ /* addrmap1.addrmap_bank_b1 */
+ val = (reg & GENMASK(5, 0)) >> 0;
+ if (val <= 31)
+ bits++;
+ /* addrmap1.addrmap_bank_b2 */
+ val = (reg & GENMASK(13, 8)) >> 8;
+ if (val <= 31)
+ bits++;
+ /* addrmap1.addrmap_bank_b3 */
+ val = (reg & GENMASK(21, 16)) >> 16;
+ if (val <= 31)
+ bits++;
+
+ return bits;
+}
+
+static u8 get_nb_col(struct stm32mp1_ddrctl *ctl)
+{
+ u8 bits;
+ u32 reg, val;
+
+ /* Count column address bits, start at 2 for b0 and b1 (fixed) */
+ bits = 2;
+
+ reg = readl(&ctl->addrmap2);
+ /* addrmap2.addrmap_col_b2 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap2.addrmap_col_b3 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+ /* addrmap2.addrmap_col_b4 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 7)
+ bits++;
+ /* addrmap2.addrmap_col_b5 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 7)
+ bits++;
+
+ reg = readl(&ctl->addrmap3);
+ /* addrmap3.addrmap_col_b6 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap3.addrmap_col_b7 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+ /* addrmap3.addrmap_col_b8 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 7)
+ bits++;
+ /* addrmap3.addrmap_col_b9 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 7)
+ bits++;
+
+ reg = readl(&ctl->addrmap4);
+ /* addrmap4.addrmap_col_b10 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap4.addrmap_col_b11 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+
+ return bits;
+}
+
+static u8 get_nb_row(struct stm32mp1_ddrctl *ctl)
+{
+ /* Count row address bits */
+ u8 bits = 0;
+ u32 reg, val;
+
+ reg = readl(&ctl->addrmap5);
+ /* addrmap5.addrmap_row_b0 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 11)
+ bits++;
+ /* addrmap5.addrmap_row_b1 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 11)
+ bits++;
+ /* addrmap5.addrmap_row_b2_10 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 11)
+ bits += 9;
+ else
+ printf("warning: addrmap5.addrmap_row_b2_10 not supported\n");
+ /* addrmap5.addrmap_row_b11 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 11)
+ bits++;
+
+ reg = readl(&ctl->addrmap6);
+ /* addrmap6.addrmap_row_b12 */
+ val = (reg & GENMASK(3, 0)) >> 0;
+ if (val <= 7)
+ bits++;
+ /* addrmap6.addrmap_row_b13 */
+ val = (reg & GENMASK(11, 8)) >> 8;
+ if (val <= 7)
+ bits++;
+ /* addrmap6.addrmap_row_b14 */
+ val = (reg & GENMASK(19, 16)) >> 16;
+ if (val <= 7)
+ bits++;
+ /* addrmap6.addrmap_row_b15 */
+ val = (reg & GENMASK(27, 24)) >> 24;
+ if (val <= 7)
+ bits++;
+
+ return bits;
+}
+
static void itm_soft_reset(struct stm32mp1_ddrphy *phy)
{
stm32mp1_ddrphy_init(phy, DDRPHYC_PIR_ITMSRST);
@@ -169,8 +298,13 @@ static void set_r0dgps_delay(struct stm32mp1_ddrphy *phy,
}
/* Basic BIST configuration for data lane tests. */
-static void config_BIST(struct stm32mp1_ddrphy *phy)
+static void config_BIST(struct stm32mp1_ddrctl *ctl,
+ struct stm32mp1_ddrphy *phy)
{
+ u8 nb_bank = get_nb_bank(ctl);
+ u8 nb_row = get_nb_row(ctl);
+ u8 nb_col = get_nb_col(ctl);
+
/* Selects the SDRAM bank address to be used during BIST. */
u32 bbank = 0;
/* Selects the SDRAM row address to be used during BIST. */
@@ -190,18 +324,20 @@ static void config_BIST(struct stm32mp1_ddrphy *phy)
* must be 0 with single rank
*/
u32 brank = 0;
+
/* Specifies the maximum SDRAM bank address to be used during
* BIST before the address & increments to the next rank.
*/
- u32 bmbank = 1;
+ u32 bmbank = (1 << nb_bank) - 1;
/* Specifies the maximum SDRAM row address to be used during
* BIST before the address & increments to the next bank.
*/
- u32 bmrow = 0x7FFF; /* To check */
+ u32 bmrow = (1 << nb_row) - 1;
/* Specifies the maximum SDRAM column address to be used during
* BIST before the address & increments to the next row.
*/
- u32 bmcol = 0x3FF; /* To check */
+ u32 bmcol = (1 << nb_col) - 1;
+
u32 bmode_conf = 0x00000001; /* DRam mode */
u32 bdxen_conf = 0x00000001; /* BIST on Data byte */
u32 bdpat_conf = 0x00000002; /* Select LFSR pattern */
@@ -223,8 +359,6 @@ static void config_BIST(struct stm32mp1_ddrphy *phy)
writel(bcol | (brow << 12) | (bbank << 28), &phy->bistar0);
writel(brank | (bmrank << 2) | (bainc << 4), &phy->bistar1);
-
- /* To check this line : */
writel(bmcol | (bmrow << 12) | (bmbank << 28), &phy->bistar2);
}
@@ -246,6 +380,8 @@ static void BIST_test(struct stm32mp1_ddrphy *phy, u8 byte,
bool result = true; /* BIST_SUCCESS */
u32 cnt = 0;
u32 error = 0;
+ u32 val;
+ int ret;
bist->test_result = true;
@@ -266,7 +402,7 @@ run:
writel(rand(), &phy->bistlsr);
/* some delay to reset BIST */
- mdelay(1);
+ udelay(10);
/*Perform BIST Run*/
clrsetbits_le32(&phy->bistrr,
@@ -274,27 +410,29 @@ run:
0x00000001);
/* Write BISTRR.BINST = 3?b001; */
- /* Wait for a number of CTL clocks before reading BIST register*/
- /* Wait 300 ctl_clk cycles; ... IS it really needed?? */
- /* Perform BIST Instruction Stop*/
- /* Write BISTRR.BINST = 3?b010;*/
-
- /* poll on BISTGSR.BDONE. If 0, wait. ++TODO Add timeout */
- while (!(readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDDONE))
- ;
-
- /*Check if received correct number of words*/
- /* if (Read BISTWCSR.DXWCNT = Read BISTWCR.BWCNT) */
- if (((readl(&phy->bistwcsr)) >> DDRPHYC_BISTWCSR_DXWCNT_SHIFT) ==
- readl(&phy->bistwcr)) {
- /*Determine if there is a data comparison error*/
- /* if (Read BISTGSR.BDXERR = 1?b0) */
- if (readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDXERR)
- result = false; /* BIST_FAIL; */
- else
- result = true; /* BIST_SUCCESS; */
- } else {
+ /* poll on BISTGSR.BDONE and wait max 1000 us */
+ ret = readl_poll_timeout(&phy->bistgsr, val,
+ val & DDRPHYC_BISTGSR_BDDONE, 1000);
+
+ if (ret < 0) {
+ printf("warning: BIST timeout\n");
result = false; /* BIST_FAIL; */
+ /*Perform BIST Stop */
+ clrsetbits_le32(&phy->bistrr, 0x00000007, 0x00000002);
+ } else {
+ /*Check if received correct number of words*/
+ /* if (Read BISTWCSR.DXWCNT = Read BISTWCR.BWCNT) */
+ if (((readl(&phy->bistwcsr)) >> DDRPHYC_BISTWCSR_DXWCNT_SHIFT)
+ == readl(&phy->bistwcr)) {
+ /*Determine if there is a data comparison error*/
+ /* if (Read BISTGSR.BDXERR = 1?b0) */
+ if (readl(&phy->bistgsr) & DDRPHYC_BISTGSR_BDXERR)
+ result = false; /* BIST_FAIL; */
+ else
+ result = true; /* BIST_SUCCESS; */
+ } else {
+ result = false; /* BIST_FAIL; */
+ }
}
/* loop while success */
@@ -394,7 +532,7 @@ static enum test_result bit_deskew(struct stm32mp1_ddrctl *ctl,
clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
/* Config the BIST block */
- config_BIST(phy);
+ config_BIST(ctl, phy);
pr_debug("BIST Config done.\n");
/* Train each byte */
@@ -807,7 +945,7 @@ static enum test_result eye_training(struct stm32mp1_ddrctl *ctl,
clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
/* Config the BIST block */
- config_BIST(phy);
+ config_BIST(ctl, phy);
for (byte = 0; byte < nb_bytes; byte++) {
if (ctrlc()) {
@@ -1182,15 +1320,17 @@ static u8 set_midpoint_read_dqs_gating(struct stm32mp1_ddrphy *phy, u8 byte,
dqs_gate_values[byte][0],
dqs_gate_values[byte][1]);
pr_debug("*******the nominal values were system latency: 0 phase: 2*******\n");
- set_r0dgsl_delay(phy, byte, dqs_gate_values[byte][0]);
- set_r0dgps_delay(phy, byte, dqs_gate_values[byte][1]);
}
} else {
/* if intermitant, restore defaut values */
pr_debug("dqs gating:no regular fail/pass/fail found. defaults values restored.\n");
- set_r0dgsl_delay(phy, byte, 0);
- set_r0dgps_delay(phy, byte, 2);
+ dqs_gate_values[byte][0] = 0;
+ dqs_gate_values[byte][1] = 2;
}
+ set_r0dgsl_delay(phy, byte, dqs_gate_values[byte][0]);
+ set_r0dgps_delay(phy, byte, dqs_gate_values[byte][1]);
+ printf("Byte %d, R0DGSL = %d, R0DGPS = %d\n",
+ byte, dqs_gate_values[byte][0], dqs_gate_values[byte][1]);
/* return 0 if intermittent or if both left_bound
* and right_bound are not found
@@ -1227,7 +1367,7 @@ static enum test_result read_dqs_gating(struct stm32mp1_ddrctl *ctl,
clrbits_le32(&phy->dx3gcr, DDRPHYC_DXNGCR_DXEN);
/* config the bist block */
- config_BIST(phy);
+ config_BIST(ctl, phy);
for (byte = 0; byte < nb_bytes; byte++) {
if (ctrlc()) {
@@ -1281,11 +1421,16 @@ static enum test_result do_read_dqs_gating(struct stm32mp1_ddrctl *ctl,
{
u32 rfshctl3 = readl(&ctl->rfshctl3);
u32 pwrctl = readl(&ctl->pwrctl);
+ u32 derateen = readl(&ctl->derateen);
enum test_result res;
+ writel(0x0, &ctl->derateen);
stm32mp1_refresh_disable(ctl);
+
res = read_dqs_gating(ctl, phy, string);
+
stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
+ writel(derateen, &ctl->derateen);
return res;
}
@@ -1296,11 +1441,16 @@ static enum test_result do_bit_deskew(struct stm32mp1_ddrctl *ctl,
{
u32 rfshctl3 = readl(&ctl->rfshctl3);
u32 pwrctl = readl(&ctl->pwrctl);
+ u32 derateen = readl(&ctl->derateen);
enum test_result res;
+ writel(0x0, &ctl->derateen);
stm32mp1_refresh_disable(ctl);
+
res = bit_deskew(ctl, phy, string);
+
stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
+ writel(derateen, &ctl->derateen);
return res;
}
@@ -1311,11 +1461,16 @@ static enum test_result do_eye_training(struct stm32mp1_ddrctl *ctl,
{
u32 rfshctl3 = readl(&ctl->rfshctl3);
u32 pwrctl = readl(&ctl->pwrctl);
+ u32 derateen = readl(&ctl->derateen);
enum test_result res;
+ writel(0x0, &ctl->derateen);
stm32mp1_refresh_disable(ctl);
+
res = eye_training(ctl, phy, string);
+
stm32mp1_refresh_restore(ctl, rfshctl3, pwrctl);
+ writel(derateen, &ctl->derateen);
return res;
}
diff --git a/drivers/remoteproc/ti_k3_dsp_rproc.c b/drivers/remoteproc/ti_k3_dsp_rproc.c
index 09e050ffb2..1fc8193ad9 100644
--- a/drivers/remoteproc/ti_k3_dsp_rproc.c
+++ b/drivers/remoteproc/ti_k3_dsp_rproc.c
@@ -2,9 +2,9 @@
/*
* Texas Instruments' K3 DSP Remoteproc driver
*
- * Copyright (C) 2018-2019 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2018-2020 Texas Instruments Incorporated - http://www.ti.com/
* Lokesh Vutla <lokeshvutla@ti.com>
- *
+ * Suman Anna <s-anna@ti.com>
*/
#include <common.h>
@@ -18,6 +18,7 @@
#include <power-domain.h>
#include <dm/device_compat.h>
#include <linux/err.h>
+#include <linux/sizes.h>
#include <linux/soc/ti/ti_sci_protocol.h>
#include "ti_sci_proc.h"
@@ -38,19 +39,79 @@ struct k3_dsp_mem {
};
/**
+ * struct k3_dsp_boot_data - internal data structure used for boot
+ * @boot_align_addr: Boot vector address alignment granularity
+ * @uses_lreset: Flag to denote the need for local reset management
+ */
+struct k3_dsp_boot_data {
+ u32 boot_align_addr;
+ bool uses_lreset;
+};
+
+/**
* struct k3_dsp_privdata - Structure representing Remote processor data.
* @rproc_rst: rproc reset control data
* @tsp: Pointer to TISCI proc contrl handle
+ * @data: Pointer to DSP specific boot data structure
* @mem: Array of available memories
* @num_mem: Number of available memories
*/
struct k3_dsp_privdata {
struct reset_ctl dsp_rst;
struct ti_sci_proc tsp;
+ struct k3_dsp_boot_data *data;
struct k3_dsp_mem *mem;
int num_mems;
};
+/*
+ * The C66x DSP cores have a local reset that affects only the CPU, and a
+ * generic module reset that powers on the device and allows the DSP internal
+ * memories to be accessed while the local reset is asserted. This function is
+ * used to release the global reset on C66x DSPs to allow loading into the DSP
+ * internal RAMs. This helper function is invoked in k3_dsp_load() before any
+ * actual firmware loading and is undone only in k3_dsp_stop(). The local reset
+ * on C71x cores is a no-op and the global reset cannot be released on C71x
+ * cores until after the firmware images are loaded, so this function does
+ * nothing for C71x cores.
+ */
+static int k3_dsp_prepare(struct udevice *dev)
+{
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ struct k3_dsp_boot_data *data = dsp->data;
+ int ret;
+
+ /* local reset is no-op on C71x processors */
+ if (!data->uses_lreset)
+ return 0;
+
+ ret = ti_sci_proc_power_domain_on(&dsp->tsp);
+ if (ret)
+ dev_err(dev, "cannot enable internal RAM loading, ret = %d\n",
+ ret);
+
+ return ret;
+}
+
+/*
+ * This function is the counterpart to k3_dsp_prepare() and is used to assert
+ * the global reset on C66x DSP cores (no-op for C71x DSP cores). This completes
+ * the second step of powering down the C66x DSP cores. The cores themselves
+ * are halted through the local reset in first step. This function is invoked
+ * in k3_dsp_stop() after the local reset is asserted.
+ */
+static int k3_dsp_unprepare(struct udevice *dev)
+{
+ struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ struct k3_dsp_boot_data *data = dsp->data;
+
+ /* local reset is no-op on C71x processors */
+ if (!data->uses_lreset)
+ return 0;
+
+ return ti_sci_proc_power_domain_off(&dsp->tsp);
+}
+
/**
* k3_dsp_load() - Load up the Remote processor image
* @dev: rproc device pointer
@@ -62,6 +123,7 @@ struct k3_dsp_privdata {
static int k3_dsp_load(struct udevice *dev, ulong addr, ulong size)
{
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ struct k3_dsp_boot_data *data = dsp->data;
u32 boot_vector;
int ret;
@@ -70,17 +132,33 @@ static int k3_dsp_load(struct udevice *dev, ulong addr, ulong size)
if (ret)
return ret;
+ ret = k3_dsp_prepare(dev);
+ if (ret) {
+ dev_err(dev, "DSP prepare failed for core %d\n",
+ dsp->tsp.proc_id);
+ goto proc_release;
+ }
+
ret = rproc_elf_load_image(dev, addr, size);
if (ret < 0) {
dev_err(dev, "Loading elf failed %d\n", ret);
- goto proc_release;
+ goto unprepare;
}
boot_vector = rproc_elf_get_boot_addr(dev, addr);
+ if (boot_vector & (data->boot_align_addr - 1)) {
+ ret = -EINVAL;
+ dev_err(dev, "Boot vector 0x%x not aligned on 0x%x boundary\n",
+ boot_vector, data->boot_align_addr);
+ goto proc_release;
+ }
dev_dbg(dev, "%s: Boot vector = 0x%x\n", __func__, boot_vector);
ret = ti_sci_proc_set_config(&dsp->tsp, boot_vector, 0, 0);
+unprepare:
+ if (ret)
+ k3_dsp_unprepare(dev);
proc_release:
ti_sci_proc_release(&dsp->tsp);
return ret;
@@ -95,6 +173,7 @@ proc_release:
static int k3_dsp_start(struct udevice *dev)
{
struct k3_dsp_privdata *dsp = dev_get_priv(dev);
+ struct k3_dsp_boot_data *data = dsp->data;
int ret;
dev_dbg(dev, "%s\n", __func__);
@@ -102,16 +181,18 @@ static int k3_dsp_start(struct udevice *dev)
ret = ti_sci_proc_request(&dsp->tsp);
if (ret)
return ret;
- /*
- * Setting the right clock frequency would have taken care by
- * assigned-clock-rates during the device probe. So no need to
- * set the frequency again here.
- */
- ret = ti_sci_proc_power_domain_on(&dsp->tsp);
- if (ret)
- goto proc_release;
+
+ if (!data->uses_lreset) {
+ ret = ti_sci_proc_power_domain_on(&dsp->tsp);
+ if (ret)
+ goto proc_release;
+ }
ret = reset_deassert(&dsp->dsp_rst);
+ if (ret) {
+ if (!data->uses_lreset)
+ ti_sci_proc_power_domain_off(&dsp->tsp);
+ }
proc_release:
ti_sci_proc_release(&dsp->tsp);
@@ -302,6 +383,8 @@ static int k3_dsp_of_to_priv(struct udevice *dev, struct k3_dsp_privdata *dsp)
if (ret)
return ret;
+ dsp->data = (struct k3_dsp_boot_data *)dev_get_driver_data(dev);
+
return 0;
}
@@ -326,6 +409,15 @@ static int k3_dsp_probe(struct udevice *dev)
return ret;
}
+ /*
+ * The DSP local resets are deasserted by default on Power-On-Reset.
+ * Assert the local resets to ensure the DSPs don't execute bogus code
+ * in .load() callback when the module reset is released to support
+ * internal memory loading. This is needed for C66x DSPs, and is a
+ * no-op on C71x DSPs.
+ */
+ reset_assert(&dsp->dsp_rst);
+
dev_dbg(dev, "Remoteproc successfully probed\n");
return 0;
@@ -340,9 +432,19 @@ static int k3_dsp_remove(struct udevice *dev)
return 0;
}
+static const struct k3_dsp_boot_data c66_data = {
+ .boot_align_addr = SZ_1K,
+ .uses_lreset = true,
+};
+
+static const struct k3_dsp_boot_data c71_data = {
+ .boot_align_addr = SZ_2M,
+ .uses_lreset = false,
+};
+
static const struct udevice_id k3_dsp_ids[] = {
- { .compatible = "ti,j721e-c66-dsp"},
- { .compatible = "ti,j721e-c71-dsp"},
+ { .compatible = "ti,j721e-c66-dsp", .data = (ulong)&c66_data, },
+ { .compatible = "ti,j721e-c71-dsp", .data = (ulong)&c71_data, },
{}
};
diff --git a/drivers/remoteproc/ti_k3_r5f_rproc.c b/drivers/remoteproc/ti_k3_r5f_rproc.c
index ea56689552..c01b29d90f 100644
--- a/drivers/remoteproc/ti_k3_r5f_rproc.c
+++ b/drivers/remoteproc/ti_k3_r5f_rproc.c
@@ -543,6 +543,7 @@ static int k3_r5f_rproc_configure(struct k3_r5f_core *core)
{
struct k3_r5f_cluster *cluster = core->cluster;
u32 set_cfg = 0, clr_cfg = 0, cfg, ctrl, sts;
+ bool lockstep_permitted;
u64 boot_vec = 0;
int ret;
@@ -560,8 +561,9 @@ static int k3_r5f_rproc_configure(struct k3_r5f_core *core)
goto out;
/* Sanity check for Lockstep mode */
- if (cluster->mode && is_primary_core(core) &&
- !(sts & PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED)) {
+ lockstep_permitted = !!(sts &
+ PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED);
+ if (cluster->mode && is_primary_core(core) && !lockstep_permitted) {
dev_err(core->dev, "LockStep mode not permitted on this device\n");
ret = -EINVAL;
goto out;
@@ -573,7 +575,7 @@ static int k3_r5f_rproc_configure(struct k3_r5f_core *core)
clr_cfg |= PROC_BOOT_CFG_FLAG_R5_TEINIT;
if (cluster->mode == CLUSTER_MODE_LOCKSTEP)
set_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP;
- else
+ else if (lockstep_permitted)
clr_cfg |= PROC_BOOT_CFG_FLAG_R5_LOCKSTEP;
}
@@ -816,4 +818,5 @@ U_BOOT_DRIVER(k3_r5fss) = {
.id = UCLASS_MISC,
.probe = k3_r5f_cluster_probe,
.priv_auto_alloc_size = sizeof(struct k3_r5f_cluster),
+ .flags = DM_FLAG_DEFAULT_PD_CTRL_OFF,
};
diff --git a/drivers/serial/serial_zynq.c b/drivers/serial/serial_zynq.c
index e4e4c39285..0dd6cec82a 100644
--- a/drivers/serial/serial_zynq.c
+++ b/drivers/serial/serial_zynq.c
@@ -17,8 +17,6 @@
#include <serial.h>
#include <linux/err.h>
-DECLARE_GLOBAL_DATA_PTR;
-
#define ZYNQ_UART_SR_TXACTIVE BIT(11) /* TX active */
#define ZYNQ_UART_SR_TXFULL BIT(4) /* TX FIFO full */
#define ZYNQ_UART_SR_RXEMPTY BIT(1) /* RX FIFO empty */
@@ -45,7 +43,7 @@ struct zynq_uart_platdata {
struct uart_zynq *regs;
};
-/* Set up the baud rate in gd struct */
+/* Set up the baud rate */
static void _uart_zynq_serial_setbrg(struct uart_zynq *regs,
unsigned long clock, unsigned long baud)
{
@@ -140,9 +138,12 @@ static int zynq_serial_setbrg(struct udevice *dev, int baudrate)
static int zynq_serial_probe(struct udevice *dev)
{
struct zynq_uart_platdata *platdata = dev_get_platdata(dev);
+ struct uart_zynq *regs = platdata->regs;
+ u32 val;
- /* No need to reinitialize the UART after relocation */
- if (gd->flags & GD_FLG_RELOC)
+ /* No need to reinitialize the UART if TX already enabled */
+ val = readl(&regs->control);
+ if (val & ZYNQ_UART_CR_TX_EN)
return 0;
_uart_zynq_serial_init(platdata->regs);
diff --git a/drivers/timer/sti-timer.c b/drivers/timer/sti-timer.c
index 9def7e02f4..ff42056abd 100644
--- a/drivers/timer/sti-timer.c
+++ b/drivers/timer/sti-timer.c
@@ -6,14 +6,13 @@
#include <common.h>
#include <dm.h>
-#include <fdtdec.h>
+#include <clk.h>
#include <timer.h>
+#include <linux/err.h>
#include <asm/io.h>
#include <asm/arch-armv7/globaltimer.h>
-DECLARE_GLOBAL_DATA_PTR;
-
struct sti_timer_priv {
struct globaltimer *global_timer;
};
@@ -44,13 +43,24 @@ static int sti_timer_probe(struct udevice *dev)
{
struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct sti_timer_priv *priv = dev_get_priv(dev);
- fdt_addr_t addr;
-
- uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK;
+ struct clk clk;
+ int err;
+ ulong ret;
/* get arm global timer base address */
- addr = fdtdec_get_addr(gd->fdt_blob, dev_of_offset(dev), "reg");
- priv->global_timer = (struct globaltimer *)addr;
+ priv->global_timer = (struct globaltimer *)dev_read_addr_ptr(dev);
+ if (!priv->global_timer)
+ return -ENOENT;
+
+ err = clk_get_by_index(dev, 0, &clk);
+ if (!err) {
+ ret = clk_get_rate(&clk);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+ uc_priv->clock_rate = ret;
+ } else {
+ uc_priv->clock_rate = CONFIG_SYS_HZ_CLOCK;
+ }
/* init timer */
writel(0x01, &priv->global_timer->ctl);
diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
index f947e6983c..ce846488a8 100644
--- a/drivers/usb/cdns3/core.c
+++ b/drivers/usb/cdns3/core.c
@@ -108,7 +108,7 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
enum usb_dr_mode dr_mode;
int ret = 0;
- dr_mode = usb_get_dr_mode(dev_of_offset(dev));
+ dr_mode = usb_get_dr_mode(dev->node);
cdns->role = USB_ROLE_NONE;
/*
@@ -384,22 +384,20 @@ static const struct udevice_id cdns3_ids[] = {
int cdns3_bind(struct udevice *parent)
{
- int from = dev_of_offset(parent);
- const void *fdt = gd->fdt_blob;
enum usb_dr_mode dr_mode;
struct udevice *dev;
const char *driver;
const char *name;
- int node;
+ ofnode node;
int ret;
- node = fdt_node_offset_by_compatible(fdt, from, "cdns,usb3");
- if (node < 0) {
+ node = ofnode_by_compatible(parent->node, "cdns,usb3");
+ if (!ofnode_valid(node)) {
ret = -ENODEV;
goto fail;
}
- name = fdt_get_name(fdt, node, NULL);
+ name = ofnode_get_name(node);
dr_mode = usb_get_dr_mode(node);
switch (dr_mode) {
@@ -422,8 +420,7 @@ int cdns3_bind(struct udevice *parent)
goto fail;
};
- ret = device_bind_driver_to_node(parent, driver, name,
- offset_to_ofnode(node), &dev);
+ ret = device_bind_driver_to_node(parent, driver, name, node, &dev);
if (ret) {
printf("%s: not able to bind usb device mode\n",
__func__);
diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c
index 8377eb458b..caed27c32f 100644
--- a/drivers/usb/cdns3/gadget.c
+++ b/drivers/usb/cdns3/gadget.c
@@ -2579,7 +2579,7 @@ static int cdns3_gadget_start(struct cdns3 *cdns)
if (!priv_dev->onchip_buffers)
priv_dev->onchip_buffers = 256;
- max_speed = usb_get_maximum_speed(dev_of_offset(cdns->dev));
+ max_speed = usb_get_maximum_speed(dev_ofnode(cdns->dev));
/* Check the maximum_speed parameter */
switch (max_speed) {
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
index a55def5aba..0db281b970 100644
--- a/drivers/usb/common/common.c
+++ b/drivers/usb/common/common.c
@@ -7,7 +7,7 @@
*/
#include <common.h>
-#include <linux/libfdt.h>
+#include <dm.h>
#include <linux/usb/otg.h>
#include <linux/usb/ch9.h>
@@ -20,13 +20,12 @@ static const char *const usb_dr_modes[] = {
[USB_DR_MODE_OTG] = "otg",
};
-enum usb_dr_mode usb_get_dr_mode(int node)
+enum usb_dr_mode usb_get_dr_mode(ofnode node)
{
- const void *fdt = gd->fdt_blob;
const char *dr_mode;
int i;
- dr_mode = fdt_getprop(fdt, node, "dr_mode", NULL);
+ dr_mode = ofnode_read_string(node, "dr_mode");
if (!dr_mode) {
pr_err("usb dr_mode not found\n");
return USB_DR_MODE_UNKNOWN;
@@ -48,13 +47,12 @@ static const char *const speed_names[] = {
[USB_SPEED_SUPER] = "super-speed",
};
-enum usb_device_speed usb_get_maximum_speed(int node)
+enum usb_device_speed usb_get_maximum_speed(ofnode node)
{
- const void *fdt = gd->fdt_blob;
const char *max_speed;
int i;
- max_speed = fdt_getprop(fdt, node, "maximum-speed", NULL);
+ max_speed = ofnode_read_string(node, "maximum-speed");
if (!max_speed) {
pr_err("usb maximum-speed not found\n");
return USB_SPEED_UNKNOWN;
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index 3e116b2c5c..febcfc0f54 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -88,9 +88,9 @@ static int dwc3_generic_remove(struct udevice *dev,
static int dwc3_generic_ofdata_to_platdata(struct udevice *dev)
{
struct dwc3_generic_plat *plat = dev_get_platdata(dev);
- int node = dev_of_offset(dev);
+ ofnode node = dev->node;
- plat->base = devfdt_get_addr(dev);
+ plat->base = dev_read_addr(dev);
plat->maximum_speed = usb_get_maximum_speed(node);
if (plat->maximum_speed == USB_SPEED_UNKNOWN) {
@@ -284,13 +284,11 @@ struct dwc3_glue_ops ti_ops = {
static int dwc3_glue_bind(struct udevice *parent)
{
- const void *fdt = gd->fdt_blob;
- int node;
+ ofnode node;
int ret;
- for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0;
- node = fdt_next_subnode(fdt, node)) {
- const char *name = fdt_get_name(fdt, node, NULL);
+ ofnode_for_each_subnode(node, parent->node) {
+ const char *name = ofnode_get_name(node);
enum usb_dr_mode dr_mode;
struct udevice *dev;
const char *driver = NULL;
@@ -322,7 +320,7 @@ static int dwc3_glue_bind(struct udevice *parent)
continue;
ret = device_bind_driver_to_node(parent, driver, name,
- offset_to_ofnode(node), &dev);
+ node, &dev);
if (ret) {
debug("%s: not able to bind usb device mode\n",
__func__);
@@ -400,7 +398,7 @@ static int dwc3_glue_probe(struct udevice *dev)
while (child) {
enum usb_dr_mode dr_mode;
- dr_mode = usb_get_dr_mode(dev_of_offset(child));
+ dr_mode = usb_get_dr_mode(child->node);
device_find_next_child(&child);
if (ops && ops->select_dr_mode)
ops->select_dr_mode(dev, index, dr_mode);
diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c
index 832bcd70ff..d4453f8784 100644
--- a/drivers/usb/dwc3/dwc3-meson-g12a.c
+++ b/drivers/usb/dwc3/dwc3-meson-g12a.c
@@ -393,7 +393,7 @@ static int dwc3_meson_g12a_probe(struct udevice *dev)
}
#endif
- priv->otg_mode = usb_get_dr_mode(dev_of_offset(dev));
+ priv->otg_mode = usb_get_dr_mode(dev->node);
ret = dwc3_meson_g12a_usb_init(priv);
if (ret)
diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c
index 496abf38e7..b9c814cf73 100644
--- a/drivers/usb/gadget/dwc2_udc_otg.c
+++ b/drivers/usb/gadget/dwc2_udc_otg.c
@@ -1039,13 +1039,12 @@ void dwc2_phy_shutdown(struct udevice *dev, struct phy *usb_phys, int num_phys)
static int dwc2_udc_otg_ofdata_to_platdata(struct udevice *dev)
{
struct dwc2_plat_otg_data *platdata = dev_get_platdata(dev);
- int node = dev_of_offset(dev);
ulong drvdata;
void (*set_params)(struct dwc2_plat_otg_data *data);
int ret;
- if (usb_get_dr_mode(node) != USB_DR_MODE_PERIPHERAL &&
- usb_get_dr_mode(node) != USB_DR_MODE_OTG) {
+ if (usb_get_dr_mode(dev->node) != USB_DR_MODE_PERIPHERAL &&
+ usb_get_dr_mode(dev->node) != USB_DR_MODE_OTG) {
dev_dbg(dev, "Invalid mode\n");
return -ENODEV;
}
diff --git a/drivers/usb/host/dwc3-of-simple.c b/drivers/usb/host/dwc3-of-simple.c
index 45df614b09..e4abc6f3b9 100644
--- a/drivers/usb/host/dwc3-of-simple.c
+++ b/drivers/usb/host/dwc3-of-simple.c
@@ -12,7 +12,6 @@
#include <common.h>
#include <dm.h>
-#include <fdtdec.h>
#include <reset.h>
#include <clk.h>
diff --git a/drivers/usb/host/dwc3-sti-glue.c b/drivers/usb/host/dwc3-sti-glue.c
index ad7cf6e6b5..c99a1985cc 100644
--- a/drivers/usb/host/dwc3-sti-glue.c
+++ b/drivers/usb/host/dwc3-sti-glue.c
@@ -10,8 +10,6 @@
#include <asm/io.h>
#include <dm.h>
#include <errno.h>
-#include <fdtdec.h>
-#include <linux/libfdt.h>
#include <dm/lists.h>
#include <regmap.h>
#include <reset-uclass.h>
@@ -109,8 +107,7 @@ static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev)
int ret;
u32 reg[4];
- ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev),
- "reg", reg, ARRAY_SIZE(reg));
+ ret = ofnode_read_u32_array(dev->node, "reg", reg, ARRAY_SIZE(reg));
if (ret) {
pr_err("unable to find st,stih407-dwc3 reg property(%d)\n", ret);
return ret;
@@ -153,18 +150,15 @@ static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev)
static int sti_dwc3_glue_bind(struct udevice *dev)
{
struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev);
- int dwc3_node;
+ ofnode node, dwc3_node;
- /* check if one subnode is present */
- dwc3_node = fdt_first_subnode(gd->fdt_blob, dev_of_offset(dev));
- if (dwc3_node <= 0) {
- pr_err("Can't find subnode for %s\n", dev->name);
- return -ENODEV;
+ /* Find snps,dwc3 node from subnode */
+ ofnode_for_each_subnode(node, dev->node) {
+ if (ofnode_device_is_compatible(node, "snps,dwc3"))
+ dwc3_node = node;
}
- /* check if the subnode compatible string is the dwc3 one*/
- if (fdt_node_check_compatible(gd->fdt_blob, dwc3_node,
- "snps,dwc3") != 0) {
+ if (!ofnode_valid(node)) {
pr_err("Can't find dwc3 subnode for %s\n", dev->name);
return -ENODEV;
}
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 5c257ccf4d..dd92808ff7 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -10,8 +10,6 @@
#include <common.h>
#include <dm.h>
#include <errno.h>
-#include <fdtdec.h>
-#include <linux/libfdt.h>
#include <usb.h>
#include <usb/ehci-ci.h>
#include <usb/ulpi.h>
@@ -108,7 +106,7 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
struct msm_ehci_priv *priv = dev_get_priv(dev);
priv->ulpi_vp.port_num = 0;
- priv->ehci = (void *)devfdt_get_addr(dev);
+ priv->ehci = dev_read_addr_ptr(dev);
if (priv->ehci == (void *)FDT_ADDR_T_NONE)
return -EINVAL;
diff --git a/drivers/usb/host/ehci-mx6.c b/drivers/usb/host/ehci-mx6.c
index 1993ad620a..f2ceb51310 100644
--- a/drivers/usb/host/ehci-mx6.c
+++ b/drivers/usb/host/ehci-mx6.c
@@ -513,7 +513,7 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
struct usb_platdata *plat = dev_get_platdata(dev);
enum usb_dr_mode dr_mode;
- dr_mode = usb_get_dr_mode(dev_of_offset(dev));
+ dr_mode = usb_get_dr_mode(dev->node);
switch (dr_mode) {
case USB_DR_MODE_HOST:
diff --git a/drivers/usb/host/xhci-dwc3.c b/drivers/usb/host/xhci-dwc3.c
index c1c681ca6c..9fcfa39d4b 100644
--- a/drivers/usb/host/xhci-dwc3.c
+++ b/drivers/usb/host/xhci-dwc3.c
@@ -9,7 +9,6 @@
#include <common.h>
#include <dm.h>
-#include <fdtdec.h>
#include <generic-phy.h>
#include <usb.h>
#include <dwc3-uboot.h>
@@ -155,7 +154,7 @@ static int xhci_dwc3_probe(struct udevice *dev)
writel(reg, &dwc3_reg->g_usb2phycfg[0]);
- dr_mode = usb_get_dr_mode(dev_of_offset(dev));
+ dr_mode = usb_get_dr_mode(dev->node);
if (dr_mode == USB_DR_MODE_UNKNOWN)
/* by default set dual role mode to HOST */
dr_mode = USB_DR_MODE_HOST;
diff --git a/drivers/usb/musb-new/ti-musb.c b/drivers/usb/musb-new/ti-musb.c
index 00759f3e83..608facefa3 100644
--- a/drivers/usb/musb-new/ti-musb.c
+++ b/drivers/usb/musb-new/ti-musb.c
@@ -285,14 +285,12 @@ U_BOOT_DRIVER(ti_musb_peripheral) = {
#if CONFIG_IS_ENABLED(OF_CONTROL)
static int ti_musb_wrapper_bind(struct udevice *parent)
{
- const void *fdt = gd->fdt_blob;
- int node;
+ ofnode node;
int ret;
- for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0;
- node = fdt_next_subnode(fdt, node)) {
+ ofnode_for_each_subnode(node, parent->node) {
struct udevice *dev;
- const char *name = fdt_get_name(fdt, node, NULL);
+ const char *name = ofnode_get_name(node);
enum usb_dr_mode dr_mode;
struct driver *drv;
@@ -306,7 +304,7 @@ static int ti_musb_wrapper_bind(struct udevice *parent)
ret = device_bind_driver_to_node(parent,
"ti-musb-peripheral",
name,
- offset_to_ofnode(node),
+ node,
&dev);
if (ret)
pr_err("musb - not able to bind usb peripheral node\n");
@@ -316,7 +314,7 @@ static int ti_musb_wrapper_bind(struct udevice *parent)
ret = device_bind_driver_to_node(parent,
"ti-musb-host",
name,
- offset_to_ofnode(node),
+ node,
&dev);
if (ret)
pr_err("musb - not able to bind usb host node\n");
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 4c93369702..7c5012a67f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -473,6 +473,12 @@ config ATMEL_HLCD
help
HLCDC supports video output to an attached LCD panel.
+config AM335X_LCD
+ bool "Enable AM335x video support"
+ depends on DM_VIDEO
+ help
+ Supports video output to an attached LCD panel.
+
config LOGICORE_DP_TX
bool "Enable Logicore DP TX driver"
depends on DISPLAY
diff --git a/drivers/video/am335x-fb.c b/drivers/video/am335x-fb.c
index 51c1af587f..eb5add2a20 100644
--- a/drivers/video/am335x-fb.c
+++ b/drivers/video/am335x-fb.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2013-2018 Hannes Schmelzer <oe5hpm@oevsv.at>
* B&R Industrial Automation GmbH - http://www.br-automation.com
+ * Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
*
* minimal framebuffer driver for TI's AM335x SoC to be compatible with
* Wolfgang Denk's LCD-Framework (CONFIG_LCD, common/lcd.c)
@@ -11,61 +12,69 @@
* - starts output DMA from gd->fb_base buffer
*/
#include <common.h>
+#include <dm.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <asm/arch/omap.h>
#include <asm/arch/clock.h>
#include <asm/arch/sys_proto.h>
+#include <asm/utils.h>
+#include <linux/err.h>
#include <lcd.h>
+#include <video.h>
#include "am335x-fb.h"
-#if !defined(LCD_CNTL_BASE)
-#error "hw-base address of LCD-Controller (LCD_CNTL_BASE) not defined!"
-#endif
-
#define LCDC_FMAX 200000000
/* LCD Control Register */
-#define LCD_CLK_DIVISOR(x) ((x) << 8)
-#define LCD_RASTER_MODE 0x01
+#define LCDC_CTRL_CLK_DIVISOR_MASK GENMASK(15, 8)
+#define LCDC_CTRL_RASTER_MODE BIT(0)
+#define LCDC_CTRL_CLK_DIVISOR(x) (((x) & GENMASK(7, 0)) << 8)
/* LCD Clock Enable Register */
-#define LCD_CORECLKEN (0x01 << 0)
-#define LCD_LIDDCLKEN (0x01 << 1)
-#define LCD_DMACLKEN (0x01 << 2)
+#define LCDC_CLKC_ENABLE_CORECLKEN BIT(0)
+#define LCDC_CLKC_ENABLE_LIDDCLKEN BIT(1)
+#define LCDC_CLKC_ENABLE_DMACLKEN BIT(2)
/* LCD DMA Control Register */
-#define LCD_DMA_BURST_SIZE(x) ((x) << 4)
-#define LCD_DMA_BURST_1 0x0
-#define LCD_DMA_BURST_2 0x1
-#define LCD_DMA_BURST_4 0x2
-#define LCD_DMA_BURST_8 0x3
-#define LCD_DMA_BURST_16 0x4
+#define LCDC_DMA_CTRL_BURST_SIZE(x) (((x) & GENMASK(2, 0)) << 4)
+#define LCDC_DMA_CTRL_BURST_1 0x0
+#define LCDC_DMA_CTRL_BURST_2 0x1
+#define LCDC_DMA_CTRL_BURST_4 0x2
+#define LCDC_DMA_CTRL_BURST_8 0x3
+#define LCDC_DMA_CTRL_BURST_16 0x4
+#define LCDC_DMA_CTRL_FIFO_TH(x) (((x) & GENMASK(2, 0)) << 8)
/* LCD Timing_0 Register */
-#define LCD_HBPLSB(x) ((((x)-1) & 0xFF) << 24)
-#define LCD_HFPLSB(x) ((((x)-1) & 0xFF) << 16)
-#define LCD_HSWLSB(x) ((((x)-1) & 0x3F) << 10)
-#define LCD_HORLSB(x) (((((x) >> 4)-1) & 0x3F) << 4)
-#define LCD_HORMSB(x) (((((x) >> 4)-1) & 0x40) >> 4)
+#define LCDC_RASTER_TIMING_0_HORMSB(x) ((((x) - 1) & BIT(10)) >> 7)
+#define LCDC_RASTER_TIMING_0_HORLSB(x) (((((x) >> 4) - 1) & GENMASK(5, 0)) << 4)
+#define LCDC_RASTER_TIMING_0_HSWLSB(x) ((((x) - 1) & GENMASK(5, 0)) << 10)
+#define LCDC_RASTER_TIMING_0_HFPLSB(x) ((((x) - 1) & GENMASK(7, 0)) << 16)
+#define LCDC_RASTER_TIMING_0_HBPLSB(x) ((((x) - 1) & GENMASK(7, 0)) << 24)
/* LCD Timing_1 Register */
-#define LCD_VBP(x) ((x) << 24)
-#define LCD_VFP(x) ((x) << 16)
-#define LCD_VSW(x) (((x)-1) << 10)
-#define LCD_VERLSB(x) (((x)-1) & 0x3FF)
+#define LCDC_RASTER_TIMING_1_VERLSB(x) (((x) - 1) & GENMASK(9, 0))
+#define LCDC_RASTER_TIMING_1_VSW(x) ((((x) - 1) & GENMASK(5, 0)) << 10)
+#define LCDC_RASTER_TIMING_1_VFP(x) (((x) & GENMASK(7, 0)) << 16)
+#define LCDC_RASTER_TIMING_1_VBP(x) (((x) & GENMASK(7, 0)) << 24)
/* LCD Timing_2 Register */
-#define LCD_HSWMSB(x) ((((x)-1) & 0x3C0) << 21)
-#define LCD_VERMSB(x) ((((x)-1) & 0x400) << 16)
-#define LCD_HBPMSB(x) ((((x)-1) & 0x300) >> 4)
-#define LCD_HFPMSB(x) ((((x)-1) & 0x300) >> 8)
-#define LCD_INVMASK(x) ((x) & 0x3F00000)
+#define LCDC_RASTER_TIMING_2_HFPMSB(x) ((((x) - 1) & GENMASK(9, 8)) >> 8)
+#define LCDC_RASTER_TIMING_2_HBPMSB(x) ((((x) - 1) & GENMASK(9, 8)) >> 4)
+#define LCDC_RASTER_TIMING_2_ACB(x) (((x) & GENMASK(7, 0)) << 8)
+#define LCDC_RASTER_TIMING_2_ACBI(x) (((x) & GENMASK(3, 0)) << 16)
+#define LCDC_RASTER_TIMING_2_VSYNC_INVERT BIT(20)
+#define LCDC_RASTER_TIMING_2_HSYNC_INVERT BIT(21)
+#define LCDC_RASTER_TIMING_2_PXCLK_INVERT BIT(22)
+#define LCDC_RASTER_TIMING_2_DE_INVERT BIT(23)
+#define LCDC_RASTER_TIMING_2_HSVS_RISEFALL BIT(24)
+#define LCDC_RASTER_TIMING_2_HSVS_CONTROL BIT(25)
+#define LCDC_RASTER_TIMING_2_VERMSB(x) ((((x) - 1) & BIT(10)) << 16)
+#define LCDC_RASTER_TIMING_2_HSWMSB(x) ((((x) - 1) & GENMASK(9, 6)) << 21)
/* LCD Raster Ctrl Register */
-#define LCD_TFT_24BPP_MODE (1 << 25)
-#define LCD_TFT_24BPP_UNPACK (1 << 26)
-#define LCD_PALMODE_RAWDATA (0x02 << 20)
-#define LCD_TFT_MODE (0x01 << 7)
-#define LCD_RASTER_ENABLE (0x01 << 0)
-
-
-/* Macro definitions */
-#define FBSIZE(x) ((x->hactive * x->vactive * x->bpp) >> 3)
+#define LCDC_RASTER_CTRL_ENABLE BIT(0)
+#define LCDC_RASTER_CTRL_TFT_MODE BIT(7)
+#define LCDC_RASTER_CTRL_DATA_ORDER BIT(8)
+#define LCDC_RASTER_CTRL_REQDLY(x) (((x) & GENMASK(7, 0)) << 12)
+#define LCDC_RASTER_CTRL_PALMODE_RAWDATA (0x02 << 20)
+#define LCDC_RASTER_CTRL_TFT_ALT_ENABLE BIT(23)
+#define LCDC_RASTER_CTRL_TFT_24BPP_MODE BIT(25)
+#define LCDC_RASTER_CTRL_TFT_24BPP_UNPACK BIT(26)
struct am335x_lcdhw {
unsigned int pid; /* 0x00 */
@@ -99,10 +108,106 @@ struct am335x_lcdhw {
unsigned int clkc_reset; /* 0x70 */
};
-static struct am335x_lcdhw *lcdhw = (void *)LCD_CNTL_BASE;
+struct dpll_data {
+ unsigned long rounded_rate;
+ u16 rounded_m;
+ u8 rounded_n;
+ u8 rounded_div;
+};
DECLARE_GLOBAL_DATA_PTR;
+/**
+ * am335x_dpll_round_rate() - Round a target rate for an OMAP DPLL
+ *
+ * @dpll_data: struct dpll_data pointer for the DPLL
+ * @rate: New DPLL clock rate
+ * @return rounded rate and the computed m, n and div values in the dpll_data
+ * structure, or -ve error code.
+ */
+static ulong am335x_dpll_round_rate(struct dpll_data *dd, ulong rate)
+{
+ unsigned int m, n, d;
+ unsigned long rounded_rate;
+ int err, err_r;
+
+ dd->rounded_rate = -EFAULT;
+ err = rate;
+ err_r = err;
+
+ for (d = 2; err && d < 255; d++) {
+ for (m = 2; m < 2047; m++) {
+ if ((V_OSCK * m) < (rate * d))
+ continue;
+
+ n = (V_OSCK * m) / (rate * d);
+ if (n > 127)
+ break;
+
+ if (((V_OSCK * m) / n) > LCDC_FMAX)
+ break;
+
+ rounded_rate = (V_OSCK * m) / n / d;
+ err = abs(rounded_rate - rate);
+ if (err < err_r) {
+ err_r = err;
+ dd->rounded_rate = rounded_rate;
+ dd->rounded_m = m;
+ dd->rounded_n = n;
+ dd->rounded_div = d;
+ if (err == 0)
+ break;
+ }
+ }
+ }
+
+ debug("DPLL display: best error %d Hz (M %d, N %d, DIV %d)\n",
+ err_r, dd->rounded_m, dd->rounded_n, dd->rounded_div);
+
+ return dd->rounded_rate;
+}
+
+/**
+ * am335x_fb_set_pixel_clk_rate() - Set pixel clock rate.
+ *
+ * @am335x_lcdhw: Base address of the LCD controller registers.
+ * @rate: New clock rate in Hz.
+ * @return new rate, or -ve error code.
+ */
+static ulong am335x_fb_set_pixel_clk_rate(struct am335x_lcdhw *regs, ulong rate)
+{
+ struct dpll_params dpll_disp = { 1, 0, 1, -1, -1, -1, -1 };
+ struct dpll_data dd;
+ ulong round_rate;
+ u32 reg;
+
+ round_rate = am335x_dpll_round_rate(&dd, rate);
+ if (IS_ERR_VALUE(round_rate))
+ return round_rate;
+
+ dpll_disp.m = dd.rounded_m;
+ dpll_disp.n = dd.rounded_n;
+ do_setup_dpll(&dpll_disp_regs, &dpll_disp);
+
+ reg = readl(&regs->ctrl) & ~LCDC_CTRL_CLK_DIVISOR_MASK;
+ reg |= LCDC_CTRL_CLK_DIVISOR(dd.rounded_div);
+ writel(reg, &regs->ctrl);
+ return round_rate;
+}
+
+#if !CONFIG_IS_ENABLED(DM_VIDEO)
+
+#if !defined(LCD_CNTL_BASE)
+#error "hw-base address of LCD-Controller (LCD_CNTL_BASE) not defined!"
+#endif
+
+/* Macro definitions */
+#define FBSIZE(x) (((x)->hactive * (x)->vactive * (x)->bpp) >> 3)
+
+#define LCDC_RASTER_TIMING_2_INVMASK(x) ((x) & GENMASK(25, 20))
+
+static struct am335x_lcdhw *lcdhw = (void *)LCD_CNTL_BASE;
+
int lcd_get_size(int *line_length)
{
*line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;
@@ -112,11 +217,9 @@ int lcd_get_size(int *line_length)
int am335xfb_init(struct am335x_lcdpanel *panel)
{
u32 raster_ctrl = 0;
-
struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
- struct dpll_params dpll_disp = { 1, 0, 1, -1, -1, -1, -1 };
- unsigned int m, n, d, best_d = 2;
- int err = 0, err_r = 0;
+ ulong rate;
+ u32 reg;
if (gd->fb_base == 0) {
printf("ERROR: no valid fb_base stored in GLOBAL_DATA_PTR!\n");
@@ -132,10 +235,10 @@ int am335xfb_init(struct am335x_lcdpanel *panel)
case 16:
break;
case 32:
- raster_ctrl |= LCD_TFT_24BPP_UNPACK;
+ raster_ctrl |= LCDC_RASTER_CTRL_TFT_24BPP_UNPACK;
/* fallthrough */
case 24:
- raster_ctrl |= LCD_TFT_24BPP_MODE;
+ raster_ctrl |= LCDC_RASTER_CTRL_TFT_24BPP_MODE;
break;
default:
pr_err("am335x-fb: invalid bpp value: %d\n", panel->bpp);
@@ -157,32 +260,9 @@ int am335xfb_init(struct am335x_lcdpanel *panel)
debug("using frambuffer at 0x%08x with size %d.\n",
(unsigned int)gd->fb_base, FBSIZE(panel));
- /* setup display pll for requested clock frequency */
- err = panel->pxl_clk;
- err_r = err;
-
- for (d = 2; d < 255; d++) {
- for (m = 2; m < 2047; m++) {
- if ((V_OSCK * m) < (panel->pxl_clk * d))
- continue;
- n = (V_OSCK * m) / (panel->pxl_clk * d);
- if (n > 127)
- break;
- if (((V_OSCK * m) / n) > LCDC_FMAX)
- break;
-
- err = abs((V_OSCK * m) / n / d - panel->pxl_clk);
- if (err < err_r) {
- err_r = err;
- dpll_disp.m = m;
- dpll_disp.n = n;
- best_d = d;
- }
- }
- }
- debug("%s: PLL: best error %d Hz (M %d, N %d, DISP %d)\n",
- __func__, err_r, dpll_disp.m, dpll_disp.n, best_d);
- do_setup_dpll(&dpll_disp_regs, &dpll_disp);
+ rate = am335x_fb_set_pixel_clk_rate(lcdhw, panel->pxl_clk);
+ if (IS_ERR_VALUE(rate))
+ return rate;
/* clock source for LCDC from dispPLL M2 */
writel(0x0, &cmdpll->clklcdcpixelclk);
@@ -199,37 +279,340 @@ int am335xfb_init(struct am335x_lcdpanel *panel)
debug("am335x-fb: wait for stable power ...\n");
mdelay(panel->pup_delay);
- lcdhw->clkc_enable = LCD_CORECLKEN | LCD_LIDDCLKEN | LCD_DMACLKEN;
+ lcdhw->clkc_enable = LCDC_CLKC_ENABLE_CORECLKEN |
+ LCDC_CLKC_ENABLE_LIDDCLKEN | LCDC_CLKC_ENABLE_DMACLKEN;
lcdhw->raster_ctrl = 0;
- lcdhw->ctrl = LCD_CLK_DIVISOR(best_d) | LCD_RASTER_MODE;
+
+ reg = lcdhw->ctrl & LCDC_CTRL_CLK_DIVISOR_MASK;
+ reg |= LCDC_CTRL_RASTER_MODE;
+ lcdhw->ctrl = reg;
+
lcdhw->lcddma_fb0_base = gd->fb_base;
lcdhw->lcddma_fb0_ceiling = gd->fb_base + FBSIZE(panel);
lcdhw->lcddma_fb1_base = gd->fb_base;
lcdhw->lcddma_fb1_ceiling = gd->fb_base + FBSIZE(panel);
- lcdhw->lcddma_ctrl = LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16);
-
- lcdhw->raster_timing0 = LCD_HORLSB(panel->hactive) |
- LCD_HORMSB(panel->hactive) |
- LCD_HFPLSB(panel->hfp) |
- LCD_HBPLSB(panel->hbp) |
- LCD_HSWLSB(panel->hsw);
- lcdhw->raster_timing1 = LCD_VBP(panel->vbp) |
- LCD_VFP(panel->vfp) |
- LCD_VSW(panel->vsw) |
- LCD_VERLSB(panel->vactive);
- lcdhw->raster_timing2 = LCD_HSWMSB(panel->hsw) |
- LCD_VERMSB(panel->vactive) |
- LCD_INVMASK(panel->pol) |
- LCD_HBPMSB(panel->hbp) |
- LCD_HFPMSB(panel->hfp) |
+ lcdhw->lcddma_ctrl = LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_16);
+
+ lcdhw->raster_timing0 = LCDC_RASTER_TIMING_0_HORLSB(panel->hactive) |
+ LCDC_RASTER_TIMING_0_HORMSB(panel->hactive) |
+ LCDC_RASTER_TIMING_0_HFPLSB(panel->hfp) |
+ LCDC_RASTER_TIMING_0_HBPLSB(panel->hbp) |
+ LCDC_RASTER_TIMING_0_HSWLSB(panel->hsw);
+ lcdhw->raster_timing1 = LCDC_RASTER_TIMING_1_VBP(panel->vbp) |
+ LCDC_RASTER_TIMING_1_VFP(panel->vfp) |
+ LCDC_RASTER_TIMING_1_VSW(panel->vsw) |
+ LCDC_RASTER_TIMING_1_VERLSB(panel->vactive);
+ lcdhw->raster_timing2 = LCDC_RASTER_TIMING_2_HSWMSB(panel->hsw) |
+ LCDC_RASTER_TIMING_2_VERMSB(panel->vactive) |
+ LCDC_RASTER_TIMING_2_INVMASK(panel->pol) |
+ LCDC_RASTER_TIMING_2_HBPMSB(panel->hbp) |
+ LCDC_RASTER_TIMING_2_HFPMSB(panel->hfp) |
0x0000FF00; /* clk cycles for ac-bias */
lcdhw->raster_ctrl = raster_ctrl |
- LCD_PALMODE_RAWDATA |
- LCD_TFT_MODE |
- LCD_RASTER_ENABLE;
+ LCDC_RASTER_CTRL_PALMODE_RAWDATA |
+ LCDC_RASTER_CTRL_TFT_MODE |
+ LCDC_RASTER_CTRL_ENABLE;
debug("am335x-fb: waiting picture to be stable.\n.");
mdelay(panel->pon_delay);
return 0;
}
+
+#else /* CONFIG_DM_VIDEO */
+
+#define FBSIZE(t, p) (((t)->hactive.typ * (t)->vactive.typ * (p)->bpp) >> 3)
+
+enum {
+ LCD_MAX_WIDTH = 2048,
+ LCD_MAX_HEIGHT = 2048,
+ LCD_MAX_LOG2_BPP = VIDEO_BPP32,
+};
+
+/**
+ * tilcdc_panel_info: Panel parameters
+ *
+ * @ac_bias: AC Bias Pin Frequency
+ * @ac_bias_intrpt: AC Bias Pin Transitions per Interrupt
+ * @dma_burst_sz: DMA burst size
+ * @bpp: Bits per pixel
+ * @fdd: FIFO DMA Request Delay
+ * @tft_alt_mode: TFT Alternative Signal Mapping (Only for active)
+ * @invert_pxl_clk: Invert pixel clock
+ * @sync_edge: Horizontal and Vertical Sync Edge: 0=rising 1=falling
+ * @sync_ctrl: Horizontal and Vertical Sync: Control: 0=ignore
+ * @raster_order: Raster Data Order Select: 1=Most-to-least 0=Least-to-most
+ * @fifo_th: DMA FIFO threshold
+ */
+struct tilcdc_panel_info {
+ u32 ac_bias;
+ u32 ac_bias_intrpt;
+ u32 dma_burst_sz;
+ u32 bpp;
+ u32 fdd;
+ bool tft_alt_mode;
+ bool invert_pxl_clk;
+ u32 sync_edge;
+ u32 sync_ctrl;
+ u32 raster_order;
+ u32 fifo_th;
+};
+
+struct am335x_fb_priv {
+ struct am335x_lcdhw *regs;
+ struct tilcdc_panel_info panel;
+ struct display_timing timing;
+};
+
+static int am335x_fb_remove(struct udevice *dev)
+{
+ struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
+
+ uc_plat->base -= 0x20;
+ uc_plat->size += 0x20;
+ return 0;
+}
+
+static int am335x_fb_probe(struct udevice *dev)
+{
+ struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
+ struct video_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct am335x_fb_priv *priv = dev_get_priv(dev);
+ struct am335x_lcdhw *regs = priv->regs;
+ struct tilcdc_panel_info *panel = &priv->panel;
+ struct display_timing *timing = &priv->timing;
+ struct cm_dpll *const cmdpll = (struct cm_dpll *)CM_DPLL;
+ u32 reg;
+
+ /* Before relocation we don't need to do anything */
+ if (!(gd->flags & GD_FLG_RELOC))
+ return 0;
+
+ am335x_fb_set_pixel_clk_rate(regs, timing->pixelclock.typ);
+
+ /* clock source for LCDC from dispPLL M2 */
+ writel(0, &cmdpll->clklcdcpixelclk);
+
+ /* palette default entry */
+ memset((void *)uc_plat->base, 0, 0x20);
+ *(unsigned int *)uc_plat->base = 0x4000;
+ /* point fb behind palette */
+ uc_plat->base += 0x20;
+ uc_plat->size -= 0x20;
+
+ writel(LCDC_CLKC_ENABLE_CORECLKEN | LCDC_CLKC_ENABLE_LIDDCLKEN |
+ LCDC_CLKC_ENABLE_DMACLKEN, &regs->clkc_enable);
+ writel(0, &regs->raster_ctrl);
+
+ reg = readl(&regs->ctrl) & LCDC_CTRL_CLK_DIVISOR_MASK;
+ reg |= LCDC_CTRL_RASTER_MODE;
+ writel(reg, &regs->ctrl);
+
+ writel(uc_plat->base, &regs->lcddma_fb0_base);
+ writel(uc_plat->base + FBSIZE(timing, panel),
+ &regs->lcddma_fb0_ceiling);
+ writel(uc_plat->base, &regs->lcddma_fb1_base);
+ writel(uc_plat->base + FBSIZE(timing, panel),
+ &regs->lcddma_fb1_ceiling);
+
+ reg = LCDC_DMA_CTRL_FIFO_TH(panel->fifo_th);
+ switch (panel->dma_burst_sz) {
+ case 1:
+ reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_1);
+ break;
+ case 2:
+ reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_2);
+ break;
+ case 4:
+ reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_4);
+ break;
+ case 8:
+ reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_8);
+ break;
+ case 16:
+ reg |= LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_BURST_16);
+ break;
+ }
+
+ writel(reg, &regs->lcddma_ctrl);
+
+ writel(LCDC_RASTER_TIMING_0_HORLSB(timing->hactive.typ) |
+ LCDC_RASTER_TIMING_0_HORMSB(timing->hactive.typ) |
+ LCDC_RASTER_TIMING_0_HFPLSB(timing->hfront_porch.typ) |
+ LCDC_RASTER_TIMING_0_HBPLSB(timing->hback_porch.typ) |
+ LCDC_RASTER_TIMING_0_HSWLSB(timing->hsync_len.typ),
+ &regs->raster_timing0);
+
+ writel(LCDC_RASTER_TIMING_1_VBP(timing->vback_porch.typ) |
+ LCDC_RASTER_TIMING_1_VFP(timing->vfront_porch.typ) |
+ LCDC_RASTER_TIMING_1_VSW(timing->vsync_len.typ) |
+ LCDC_RASTER_TIMING_1_VERLSB(timing->vactive.typ),
+ &regs->raster_timing1);
+
+ reg = LCDC_RASTER_TIMING_2_ACB(panel->ac_bias) |
+ LCDC_RASTER_TIMING_2_ACBI(panel->ac_bias_intrpt) |
+ LCDC_RASTER_TIMING_2_HSWMSB(timing->hsync_len.typ) |
+ LCDC_RASTER_TIMING_2_VERMSB(timing->vactive.typ) |
+ LCDC_RASTER_TIMING_2_HBPMSB(timing->hback_porch.typ) |
+ LCDC_RASTER_TIMING_2_HFPMSB(timing->hfront_porch.typ);
+
+ if (timing->flags & DISPLAY_FLAGS_VSYNC_LOW)
+ reg |= LCDC_RASTER_TIMING_2_VSYNC_INVERT;
+
+ if (timing->flags & DISPLAY_FLAGS_HSYNC_LOW)
+ reg |= LCDC_RASTER_TIMING_2_HSYNC_INVERT;
+
+ if (panel->invert_pxl_clk)
+ reg |= LCDC_RASTER_TIMING_2_PXCLK_INVERT;
+
+ if (panel->sync_edge)
+ reg |= LCDC_RASTER_TIMING_2_HSVS_RISEFALL;
+
+ if (panel->sync_ctrl)
+ reg |= LCDC_RASTER_TIMING_2_HSVS_CONTROL;
+
+ writel(reg, &regs->raster_timing2);
+
+ reg = LCDC_RASTER_CTRL_PALMODE_RAWDATA | LCDC_RASTER_CTRL_TFT_MODE |
+ LCDC_RASTER_CTRL_ENABLE | LCDC_RASTER_CTRL_REQDLY(panel->fdd);
+
+ if (panel->tft_alt_mode)
+ reg |= LCDC_RASTER_CTRL_TFT_ALT_ENABLE;
+
+ if (panel->bpp == 24)
+ reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE;
+ else if (panel->bpp == 32)
+ reg |= LCDC_RASTER_CTRL_TFT_24BPP_MODE |
+ LCDC_RASTER_CTRL_TFT_24BPP_UNPACK;
+
+ if (panel->raster_order)
+ reg |= LCDC_RASTER_CTRL_DATA_ORDER;
+
+ writel(reg, &regs->raster_ctrl);
+
+ uc_priv->xsize = timing->hactive.typ;
+ uc_priv->ysize = timing->vactive.typ;
+ uc_priv->bpix = log_2_n_round_up(panel->bpp);
+ return 0;
+}
+
+static int am335x_fb_ofdata_to_platdata(struct udevice *dev)
+{
+ struct am335x_fb_priv *priv = dev_get_priv(dev);
+ struct tilcdc_panel_info *panel = &priv->panel;
+ struct display_timing *timing = &priv->timing;
+ ofnode node;
+ int err;
+
+ node = ofnode_by_compatible(ofnode_null(), "ti,am33xx-tilcdc");
+ if (!ofnode_valid(node)) {
+ dev_err(dev, "missing 'ti,am33xx-tilcdc' node\n");
+ return -ENXIO;
+ }
+
+ priv->regs = (struct am335x_lcdhw *)ofnode_get_addr(node);
+ dev_dbg(dev, "LCD: base address=0x%x\n", (unsigned int)priv->regs);
+
+ err = ofnode_decode_display_timing(dev_ofnode(dev), 0, timing);
+ if (err) {
+ dev_err(dev, "failed to get display timing\n");
+ return err;
+ }
+
+ if (timing->pixelclock.typ > (LCDC_FMAX / 2)) {
+ dev_err(dev, "invalid display clock-frequency: %d Hz\n",
+ timing->pixelclock.typ);
+ return -EINVAL;
+ }
+
+ if (timing->hactive.typ > LCD_MAX_WIDTH)
+ timing->hactive.typ = LCD_MAX_WIDTH;
+
+ if (timing->vactive.typ > LCD_MAX_HEIGHT)
+ timing->vactive.typ = LCD_MAX_HEIGHT;
+
+ node = ofnode_find_subnode(dev_ofnode(dev), "panel-info");
+ if (!ofnode_valid(node)) {
+ dev_err(dev, "missing 'panel-info' node\n");
+ return -ENXIO;
+ }
+
+ err |= ofnode_read_u32(node, "ac-bias", &panel->ac_bias);
+ err |= ofnode_read_u32(node, "ac-bias-intrpt", &panel->ac_bias_intrpt);
+ err |= ofnode_read_u32(node, "dma-burst-sz", &panel->dma_burst_sz);
+ err |= ofnode_read_u32(node, "bpp", &panel->bpp);
+ err |= ofnode_read_u32(node, "fdd", &panel->fdd);
+ err |= ofnode_read_u32(node, "sync-edge", &panel->sync_edge);
+ err |= ofnode_read_u32(node, "sync-ctrl", &panel->sync_ctrl);
+ err |= ofnode_read_u32(node, "raster-order", &panel->raster_order);
+ err |= ofnode_read_u32(node, "fifo-th", &panel->fifo_th);
+ if (err) {
+ dev_err(dev, "failed to get panel info\n");
+ return err;
+ }
+
+ switch (panel->bpp) {
+ case 16:
+ case 24:
+ case 32:
+ break;
+ default:
+ dev_err(dev, "invalid seting, bpp: %d\n", panel->bpp);
+ return -EINVAL;
+ }
+
+ switch (panel->dma_burst_sz) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ break;
+ default:
+ dev_err(dev, "invalid setting, dma-burst-sz: %d\n",
+ panel->dma_burst_sz);
+ return -EINVAL;
+ }
+
+ /* optional */
+ panel->tft_alt_mode = ofnode_read_bool(node, "tft-alt-mode");
+ panel->invert_pxl_clk = ofnode_read_bool(node, "invert-pxl-clk");
+
+ dev_dbg(dev, "LCD: %dx%d, bpp=%d, clk=%d Hz\n", timing->hactive.typ,
+ timing->vactive.typ, panel->bpp, timing->pixelclock.typ);
+ dev_dbg(dev, " hbp=%d, hfp=%d, hsw=%d\n", timing->hback_porch.typ,
+ timing->hfront_porch.typ, timing->hsync_len.typ);
+ dev_dbg(dev, " vbp=%d, vfp=%d, vsw=%d\n", timing->vback_porch.typ,
+ timing->vfront_porch.typ, timing->vsync_len.typ);
+
+ return 0;
+}
+
+static int am335x_fb_bind(struct udevice *dev)
+{
+ struct video_uc_platdata *uc_plat = dev_get_uclass_platdata(dev);
+
+ uc_plat->size = ((LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
+ (1 << LCD_MAX_LOG2_BPP)) >> 3) + 0x20;
+
+ dev_dbg(dev, "frame buffer size 0x%x\n", uc_plat->size);
+ return 0;
+}
+
+static const struct udevice_id am335x_fb_ids[] = {
+ { .compatible = "ti,tilcdc,panel" },
+ { }
+};
+
+U_BOOT_DRIVER(am335x_fb) = {
+ .name = "am335x_fb",
+ .id = UCLASS_VIDEO,
+ .of_match = am335x_fb_ids,
+ .bind = am335x_fb_bind,
+ .ofdata_to_platdata = am335x_fb_ofdata_to_platdata,
+ .probe = am335x_fb_probe,
+ .remove = am335x_fb_remove,
+ .priv_auto_alloc_size = sizeof(struct am335x_fb_priv),
+};
+
+#endif /* CONFIG_DM_VIDEO */
diff --git a/drivers/video/am335x-fb.h b/drivers/video/am335x-fb.h
index f5883c02dd..c9f92bc389 100644
--- a/drivers/video/am335x-fb.h
+++ b/drivers/video/am335x-fb.h
@@ -7,7 +7,9 @@
#ifndef AM335X_FB_H
#define AM335X_FB_H
-#define HSVS_CONTROL (0x01 << 25) /*
+#if !CONFIG_IS_ENABLED(DM_VIDEO)
+
+#define HSVS_CONTROL BIT(25) /*
* 0 = lcd_lp and lcd_fp are driven on
* opposite edges of pixel clock than
* the lcd_pixel_o
@@ -17,7 +19,7 @@
* Matrix displays the edge timing is
* fixed
*/
-#define HSVS_RISEFALL (0x01 << 24) /*
+#define HSVS_RISEFALL BIT(24) /*
* 0 = lcd_lp and lcd_fp are driven on
* the rising edge of pixel clock (bit
* 25 must be set to 1)
@@ -25,19 +27,19 @@
* the falling edge of pixel clock (bit
* 25 must be set to 1)
*/
-#define DE_INVERT (0x01 << 23) /*
+#define DE_INVERT BIT(23) /*
* 0 = DE is low-active
* 1 = DE is high-active
*/
-#define PXCLK_INVERT (0x01 << 22) /*
+#define PXCLK_INVERT BIT(22) /*
* 0 = pix-clk is high-active
* 1 = pic-clk is low-active
*/
-#define HSYNC_INVERT (0x01 << 21) /*
+#define HSYNC_INVERT BIT(21) /*
* 0 = HSYNC is active high
* 1 = HSYNC is avtive low
*/
-#define VSYNC_INVERT (0x01 << 20) /*
+#define VSYNC_INVERT BIT(20) /*
* 0 = VSYNC is active high
* 1 = VSYNC is active low
*/
@@ -68,4 +70,6 @@ struct am335x_lcdpanel {
int am335xfb_init(struct am335x_lcdpanel *panel);
+#endif /* CONFIG_DM_VIDEO */
+
#endif /* AM335X_FB_H */
diff --git a/drivers/video/sunxi/sunxi_display.c b/drivers/video/sunxi/sunxi_display.c
index 31f0aa7ddc..4e1720ef7e 100644
--- a/drivers/video/sunxi/sunxi_display.c
+++ b/drivers/video/sunxi/sunxi_display.c
@@ -1014,7 +1014,6 @@ static void sunxi_mode_set(const struct ctfb_res_modes *mode,
static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
{
switch (monitor) {
- case sunxi_monitor_none: return "none";
case sunxi_monitor_dvi: return "dvi";
case sunxi_monitor_hdmi: return "hdmi";
case sunxi_monitor_lcd: return "lcd";
@@ -1023,8 +1022,9 @@ static const char *sunxi_get_mon_desc(enum sunxi_monitor monitor)
case sunxi_monitor_composite_ntsc: return "composite-ntsc";
case sunxi_monitor_composite_pal_m: return "composite-pal-m";
case sunxi_monitor_composite_pal_nc: return "composite-pal-nc";
+ case sunxi_monitor_none: /* fall through */
+ default: return "none";
}
- return NULL; /* never reached */
}
ulong board_get_usable_ram_top(ulong total_size)
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index cb4da2e3cf..6cafd243e0 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -185,6 +185,15 @@ config XILINX_TB_WATCHDOG
Select this to enable Xilinx Axi watchdog timer, which can be found on some
Xilinx Microblaze Platforms.
+config WDT_XILINX
+ bool "Xilinx window watchdog timer support"
+ depends on WDT && ARCH_VERSAL
+ select REGMAP
+ imply WATCHDOG
+ help
+ Select this to enable Xilinx window watchdog timer, which can be found on
+ Xilinx Versal Platforms.
+
config WDT_TANGIER
bool "Intel Tangier watchdog timer support"
depends on WDT && INTEL_MID
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 87f92a43b1..519bbd3a40 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -30,3 +30,4 @@ obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o
obj-$(CONFIG_WDT_SP805) += sp805_wdt.o
obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o
+obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o
diff --git a/drivers/watchdog/cdns_wdt.c b/drivers/watchdog/cdns_wdt.c
index 775f06a6e1..5bf02605a8 100644
--- a/drivers/watchdog/cdns_wdt.c
+++ b/drivers/watchdog/cdns_wdt.c
@@ -15,8 +15,6 @@
#include <linux/err.h>
#include <linux/io.h>
-DECLARE_GLOBAL_DATA_PTR;
-
struct cdns_regs {
u32 zmr; /* WD Zero mode register, offset - 0x0 */
u32 ccr; /* Counter Control Register offset - 0x4 */
diff --git a/drivers/watchdog/xilinx_wwdt.c b/drivers/watchdog/xilinx_wwdt.c
new file mode 100644
index 0000000000..d8a585a483
--- /dev/null
+++ b/drivers/watchdog/xilinx_wwdt.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Xilinx window watchdog timer driver.
+ *
+ * Author(s): Michal Simek <michal.simek@xilinx.com>
+ * Ashok Reddy Soma <ashokred@xilinx.com>
+ *
+ * Copyright (c) 2020, Xilinx Inc.
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <wdt.h>
+#include <linux/compat.h>
+#include <linux/io.h>
+
+/* Refresh Register Masks */
+#define XWT_WWREF_GWRR_MASK BIT(0) /* Refresh and start new period */
+
+/* Generic Control/Status Register Masks */
+#define XWT_WWCSR_GWEN_MASK BIT(0) /* Enable Bit */
+
+/* Register offsets for the Wdt device */
+#define XWT_WWREF_OFFSET 0x1000 /* Refresh Register */
+#define XWT_WWCSR_OFFSET 0x2000 /* Control/Status Register */
+#define XWT_WWOFF_OFFSET 0x2008 /* Offset Register */
+#define XWT_WWCMP0_OFFSET 0x2010 /* Compare Value Register0 */
+#define XWT_WWCMP1_OFFSET 0x2014 /* Compare Value Register1 */
+#define XWT_WWWRST_OFFSET 0x2FD0 /* Warm Reset Register */
+
+struct xlnx_wwdt_priv {
+ bool enable_once;
+ struct regmap *regs;
+ struct clk clk;
+};
+
+struct xlnx_wwdt_platdata {
+ bool enable_once;
+};
+
+static int xlnx_wwdt_reset(struct udevice *dev)
+{
+ struct xlnx_wwdt_priv *wdt = dev_get_priv(dev);
+
+ regmap_write(wdt->regs, XWT_WWREF_OFFSET, XWT_WWREF_GWRR_MASK);
+
+ return 0;
+}
+
+static int xlnx_wwdt_stop(struct udevice *dev)
+{
+ u32 csr;
+ struct xlnx_wwdt_priv *wdt = dev_get_priv(dev);
+
+ if (wdt->enable_once) {
+ dev_warn(dev, "Can't stop Xilinx watchdog.\n");
+ return -EBUSY;
+ }
+
+ /* Disable the generic watchdog timer */
+ regmap_read(wdt->regs, XWT_WWCSR_OFFSET, &csr);
+ csr &= ~(XWT_WWCSR_GWEN_MASK);
+ regmap_write(wdt->regs, XWT_WWCSR_OFFSET, csr);
+
+ clk_disable(&wdt->clk);
+
+ dev_dbg(dev, "Watchdog disabled!\n");
+
+ return 0;
+}
+
+static int xlnx_wwdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+ int ret;
+ u32 csr;
+ u64 count;
+ unsigned long clock_f;
+ struct xlnx_wwdt_priv *wdt = dev_get_priv(dev);
+
+ clock_f = clk_get_rate(&wdt->clk);
+ if (IS_ERR_VALUE(clock_f)) {
+ dev_err(dev, "failed to get rate\n");
+ return clock_f;
+ }
+
+ dev_dbg(dev, "%s: CLK %ld\n", __func__, clock_f);
+
+ /* Calculate timeout count */
+ count = timeout * clock_f;
+
+ /* clk_enable will return -ENOSYS when it is not implemented */
+ ret = clk_enable(&wdt->clk);
+ if (ret && ret != -ENOSYS) {
+ dev_err(dev, "failed to enable clock\n");
+ return ret;
+ }
+
+ /*
+ * Timeout count is half as there are two windows
+ * first window overflow is ignored (interrupt),
+ * reset is only generated at second window overflow
+ */
+ count = count >> 1;
+
+ /* Disable the generic watchdog timer */
+ regmap_read(wdt->regs, XWT_WWCSR_OFFSET, &csr);
+ csr &= ~(XWT_WWCSR_GWEN_MASK);
+ regmap_write(wdt->regs, XWT_WWCSR_OFFSET, csr);
+
+ /* Set compare and offset registers for generic watchdog timeout */
+ regmap_write(wdt->regs, XWT_WWCMP0_OFFSET, (u32)count);
+ regmap_write(wdt->regs, XWT_WWCMP1_OFFSET, 0);
+ regmap_write(wdt->regs, XWT_WWOFF_OFFSET, (u32)count);
+
+ /* Enable the generic watchdog timer */
+ regmap_read(wdt->regs, XWT_WWCSR_OFFSET, &csr);
+ csr |= (XWT_WWCSR_GWEN_MASK);
+ regmap_write(wdt->regs, XWT_WWCSR_OFFSET, csr);
+
+ return 0;
+}
+
+static int xlnx_wwdt_probe(struct udevice *dev)
+{
+ int ret;
+ struct xlnx_wwdt_platdata *platdata = dev_get_platdata(dev);
+ struct xlnx_wwdt_priv *wdt = dev_get_priv(dev);
+
+ dev_dbg(dev, "%s: Probing wdt%u\n", __func__, dev->seq);
+
+ ret = regmap_init_mem(dev_ofnode(dev), &wdt->regs);
+ if (ret) {
+ dev_dbg(dev, "failed to get regbase of wwdt\n");
+ return ret;
+ }
+
+ wdt->enable_once = platdata->enable_once;
+
+ ret = clk_get_by_index(dev, 0, &wdt->clk);
+ if (ret < 0)
+ dev_err(dev, "failed to get clock\n");
+
+ return ret;
+}
+
+static int xlnx_wwdt_ofdata_to_platdata(struct udevice *dev)
+{
+ struct xlnx_wwdt_platdata *platdata = dev_get_platdata(dev);
+
+ platdata->enable_once = dev_read_u32_default(dev,
+ "xlnx,wdt-enable-once", 0);
+ dev_dbg(dev, "wdt-enable-once %d\n", platdata->enable_once);
+
+ return 0;
+}
+
+static const struct wdt_ops xlnx_wwdt_ops = {
+ .start = xlnx_wwdt_start,
+ .reset = xlnx_wwdt_reset,
+ .stop = xlnx_wwdt_stop,
+};
+
+static const struct udevice_id xlnx_wwdt_ids[] = {
+ { .compatible = "xlnx,versal-wwdt-1.0", },
+ {},
+};
+
+U_BOOT_DRIVER(xlnx_wwdt) = {
+ .name = "xlnx_wwdt",
+ .id = UCLASS_WDT,
+ .of_match = xlnx_wwdt_ids,
+ .probe = xlnx_wwdt_probe,
+ .priv_auto_alloc_size = sizeof(struct xlnx_wwdt_priv),
+ .platdata_auto_alloc_size = sizeof(struct xlnx_wwdt_platdata),
+ .ofdata_to_platdata = xlnx_wwdt_ofdata_to_platdata,
+ .ops = &xlnx_wwdt_ops,
+};