summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2020-03-17 11:59:58 -0400
committerTom Rini <[email protected]>2020-03-17 11:59:58 -0400
commit2738f0edea7d19960d692284d1f378b1a2b4c4a5 (patch)
tree47bc76ea90ab5395d30785b4aa83e43b15bc7a70 /drivers
parentb180e32ea39d03021655a31a19d527529a2eb980 (diff)
parent445b45042c63c79546124489362ba4e64b61bfdc (diff)
Merge tag 'ti-v2020.07-next' of https://gitlab.denx.de/u-boot/custodians/u-boot-ti into next
K3 J721E: * OSPI boot support * Support for loading remote cores in R5 SPL * PMIC ESM Support * Minor fixes for R5F and C7x remoteproc drivers K3 AM654: * Update AVS class 0 voltages. * Add I2C nodes DRA7xx/AM57xx: * Fixed Android boot on AM57xx AM33/AM43/Davinci: * switch to driver model for the net and mdio driver for baltos * Add DM/DTS support for omap video driver * Enable fastboot on am335x-evm
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile3
-rw-r--r--drivers/dma/ti/k3-udma.c7
-rw-r--r--drivers/firmware/ti_sci.c77
-rw-r--r--drivers/firmware/ti_sci.h5
-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/k3_avs.c12
-rw-r--r--drivers/misc/k3_esm.c87
-rw-r--r--drivers/power/pmic/tps65941.c4
-rw-r--r--drivers/remoteproc/ti_k3_dsp_rproc.c128
-rw-r--r--drivers/remoteproc/ti_k3_r5f_rproc.c9
-rw-r--r--drivers/video/Kconfig6
-rw-r--r--drivers/video/am335x-fb.c565
-rw-r--r--drivers/video/am335x-fb.h16
15 files changed, 794 insertions, 208 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 23501fd7438..42087504289 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/dma/ti/k3-udma.c b/drivers/dma/ti/k3-udma.c
index e587f1fcb2b..a0e536ae5e9 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/ti_sci.c b/drivers/firmware/ti_sci.c
index 99b2e5dfed4..c3f95b252f2 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 69ff74d6a95..24b4d1c7948 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/misc/Kconfig b/drivers/misc/Kconfig
index f18aa8f7ba9..766402745dd 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 2b843de93ce..68e0e7ad172 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 00000000000..92c8d68f7c8
--- /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 <[email protected]>
+ *
+ */
+
+#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/k3_avs.c b/drivers/misc/k3_avs.c
index 90df3772505..d8048e1b70b 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 00000000000..8f270f3b5cb
--- /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 <[email protected]>
+ *
+ */
+
+#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/power/pmic/tps65941.c b/drivers/power/pmic/tps65941.c
index e8f3c950bd7..7b3416ae6ec 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/remoteproc/ti_k3_dsp_rproc.c b/drivers/remoteproc/ti_k3_dsp_rproc.c
index 09e050ffb2d..1fc8193ad93 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 <[email protected]>
- *
+ * Suman Anna <[email protected]>
*/
#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 ea56689552a..c01b29d90f1 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/video/Kconfig b/drivers/video/Kconfig
index 4c933697022..7c5012a67f0 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 51c1af587f2..eb5add2a20c 100644
--- a/drivers/video/am335x-fb.c
+++ b/drivers/video/am335x-fb.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2013-2018 Hannes Schmelzer <[email protected]>
* B&R Industrial Automation GmbH - http://www.br-automation.com
+ * Copyright (C) 2020 Dario Binacchi <[email protected]>
*
* 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->lcddma_ctrl = LCDC_DMA_CTRL_BURST_SIZE(LCDC_DMA_CTRL_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->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 f5883c02ddd..c9f92bc3895 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 */