summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/button/button-qcom-pmic.c3
-rw-r--r--drivers/mailbox/Kconfig7
-rw-r--r--drivers/mailbox/Makefile1
-rw-r--r--drivers/mailbox/mpfs-mbox.c177
-rw-r--r--drivers/misc/Kconfig9
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/mpfs_syscontroller.c156
-rw-r--r--drivers/phy/qcom/phy-qcom-snps-eusb2.c3
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sa8775p.c4
-rw-r--r--drivers/pinctrl/qcom/pinctrl-sdm845.c2
-rw-r--r--drivers/serial/serial_msm_geni.c34
11 files changed, 376 insertions, 21 deletions
diff --git a/drivers/button/button-qcom-pmic.c b/drivers/button/button-qcom-pmic.c
index 85addfe32a2..b823490d6d5 100644
--- a/drivers/button/button-qcom-pmic.c
+++ b/drivers/button/button-qcom-pmic.c
@@ -195,8 +195,9 @@ static int button_qcom_pmic_bind(struct udevice *parent)
continue;
}
+ label = ofnode_get_name(node);
ret = device_bind_driver_to_node(parent, "qcom_pwrkey",
- ofnode_get_name(node),
+ label,
node, &dev);
if (ret) {
printf("Failed to bind %s! %d\n", label, ret);
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 4d9f004ebad..f9531c1627c 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -28,6 +28,13 @@ config IMX_MU_MBOX
Enable support for i.MX Messaging Unit for communication with other
processors on the SoC using mailbox interface
+config MPFS_MBOX
+ bool "Enable MPFS system controller support"
+ depends on DM_MAILBOX && ARCH_RV64I
+ help
+ Enable support for the mailboxes that provide a communication
+ channel with the system controller integrated on PolarFire SoC.
+
config SANDBOX_MBOX
bool "Enable the sandbox mailbox test driver"
depends on DM_MAILBOX && SANDBOX
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index e8c745f7d79..b54fbdfff15 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_$(PHASE_)DM_MAILBOX) += mailbox-uclass.o
obj-$(CONFIG_APPLE_MBOX) += apple-mbox.o
obj-$(CONFIG_IMX_MU_MBOX) += imx-mailbox.o
+obj-$(CONFIG_MPFS_MBOX) += mpfs-mbox.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox.o
obj-$(CONFIG_SANDBOX_MBOX) += sandbox-mbox-test.o
obj-$(CONFIG_STM32_IPCC) += stm32-ipcc.o
diff --git a/drivers/mailbox/mpfs-mbox.c b/drivers/mailbox/mpfs-mbox.c
new file mode 100644
index 00000000000..55238847ecd
--- /dev/null
+++ b/drivers/mailbox/mpfs-mbox.c
@@ -0,0 +1,177 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Microchip's PolarFire SoC (MPFS) Mailbox Driver
+ *
+ * Copyright (C) 2024 Microchip Technology Inc. All rights reserved.
+ *
+ * Author: Jamie Gibbons <jamie.gibbons@microchip.com>
+ *
+ */
+
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/devres.h>
+#include <dm/ofnode.h>
+#include <linux/bitops.h>
+#include <linux/compat.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <log.h>
+#include <mailbox-uclass.h>
+#include <malloc.h>
+#include <mpfs-mailbox.h>
+
+#define SERVICES_CR_OFFSET 0x50u
+#define SERVICES_SR_OFFSET 0x54u
+
+#define SERVICE_CR_REQ_MASK 0x1u
+#define SERVICE_SR_BUSY_MASK 0x2u
+#define SERVICE_SR_STATUS_SHIFT 16
+#define SERVICE_CR_COMMAND_SHIFT 16
+#define MASK_8BIT 0xFF
+
+struct mpfs_mbox {
+ struct udevice *dev;
+ void __iomem *ctrl_base;
+ void __iomem *mbox_base;
+ struct mbox_chan *chan;
+};
+
+static bool mpfs_mbox_busy(struct mbox_chan *chan)
+{
+ struct mpfs_mbox *mbox = dev_get_priv(chan->dev);
+ uint16_t status;
+
+ status = readl(mbox->ctrl_base + SERVICES_SR_OFFSET);
+
+ return status & SERVICE_SR_BUSY_MASK;
+}
+
+static int mpfs_mbox_send(struct mbox_chan *chan, const void *data)
+{
+ struct mpfs_mbox *mbox = dev_get_priv(chan->dev);
+ struct mpfs_mss_msg *msg = (struct mpfs_mss_msg *)data;
+ u32 mailbox_val, cmd_shifted, value;
+ u8 *byte_buf;
+ u8 idx, byte_idx, byte_offset;
+
+ u32 *word_buf = (u32 *)msg->cmd_data;
+
+ if (mpfs_mbox_busy(chan))
+ return -EBUSY;
+
+ for (idx = 0; idx < (msg->cmd_data_size / BYTES_4); idx++)
+ writel(word_buf[idx], mbox->mbox_base + msg->mbox_offset + idx * BYTES_4);
+
+ if ((msg->cmd_data_size % BYTES_4) > 0) {
+ byte_offset = (msg->cmd_data_size / BYTES_4) * BYTES_4;
+ byte_buf = (u8 *)(msg->cmd_data + byte_offset);
+ mailbox_val = readl(mbox->mbox_base + msg->mbox_offset + idx * BYTES_4);
+
+ for (byte_idx = 0; byte_idx < (msg->cmd_data_size % BYTES_4); byte_idx++) {
+ mailbox_val &= ~(MASK_8BIT << (byte_idx * 0x8u));
+ mailbox_val |= (u32)byte_buf[byte_idx] << (byte_idx * 0x8u);
+ }
+ writel(mailbox_val, mbox->mbox_base + msg->mbox_offset + idx * BYTES_4);
+ }
+
+ cmd_shifted = msg->cmd_opcode << SERVICE_CR_COMMAND_SHIFT;
+ cmd_shifted |= SERVICE_CR_REQ_MASK;
+ writel(cmd_shifted, mbox->ctrl_base + SERVICES_CR_OFFSET);
+
+ do {
+ value = readl(mbox->ctrl_base + SERVICES_CR_OFFSET);
+ } while (SERVICE_CR_REQ_MASK == (value & SERVICE_CR_REQ_MASK));
+
+ do {
+ value = readl(mbox->ctrl_base + SERVICES_SR_OFFSET);
+ } while (SERVICE_SR_BUSY_MASK == (value & SERVICE_SR_BUSY_MASK));
+
+ msg->response->resp_status = (value >> SERVICE_SR_STATUS_SHIFT);
+ if (msg->response->resp_status)
+ return -EBADMSG;
+
+ return 0;
+}
+
+static int mpfs_mbox_recv(struct mbox_chan *chan, void *data)
+{
+ struct mpfs_mbox *mbox = dev_get_priv(chan->dev);
+ struct mpfs_mss_msg *msg = data;
+ struct mpfs_mss_response *response = msg->response;
+ u8 idx;
+
+ if (!response->resp_msg) {
+ dev_err(chan->dev, "failed to assign memory for response %d\n", -ENOMEM);
+ return -EINVAL;
+ }
+
+ if (mpfs_mbox_busy(chan)) {
+ dev_err(chan->dev, "mailbox is busy\n");
+ response->resp_status = 0xDEAD;
+ return -EINVAL;
+ }
+
+ for (idx = 0; idx < response->resp_size; idx++)
+ *((u8 *)(response->resp_msg) + idx) = readb(mbox->mbox_base + msg->resp_offset + idx);
+
+ return 0;
+}
+
+static const struct mbox_ops mpfs_mbox_ops = {
+ .send = mpfs_mbox_send,
+ .recv = mpfs_mbox_recv,
+};
+
+static int mpfs_mbox_probe(struct udevice *dev)
+{
+ struct mpfs_mbox *mbox;
+ struct resource regs;
+ ofnode node;
+ int ret;
+
+ node = dev_ofnode(dev);
+
+ mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);
+ if (!mbox)
+ return -ENOMEM;
+
+ ret = ofnode_read_resource(node, 0, &regs);
+ if (ret) {
+ dev_err(dev, "No reg property for controller base\n");
+ return ret;
+ };
+
+ mbox->ctrl_base = devm_ioremap(dev, regs.start, regs.start - regs.end);
+
+ ret = ofnode_read_resource(node, 2, &regs);
+ if (ret) {
+ dev_err(dev, "No reg property for mailbox base\n");
+ return ret;
+ };
+
+ mbox->mbox_base = devm_ioremap(dev, regs.start, regs.start - regs.end);
+
+ mbox->dev = dev;
+ dev_set_priv(dev, mbox);
+ mbox->chan->con_priv = mbox;
+
+ return 0;
+}
+
+static const struct udevice_id mpfs_mbox_ids[] = {
+ {.compatible = "microchip,mpfs-mailbox"},
+ { }
+};
+
+U_BOOT_DRIVER(mpfs_mbox) = {
+ .name = "mpfs-mbox",
+ .id = UCLASS_MAILBOX,
+ .of_match = mpfs_mbox_ids,
+ .probe = mpfs_mbox_probe,
+ .priv_auto = sizeof(struct mpfs_mbox),
+ .ops = &mpfs_mbox_ops,
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0f753b9dbb9..29b84430ff5 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -658,6 +658,15 @@ config MICROCHIP_FLEXCOM
Only one function can be used at a time and is chosen at boot time
according to the device tree.
+config MPFS_SYSCONTROLLER
+ bool "Enable Microchip PolarFire SoC (MPFS) System Services support"
+ depends on MISC
+ depends on MPFS_MBOX
+ help
+ This driver adds support for the PolarFire SoC (MPFS) system controller.
+
+ If unsure, say N.
+
config K3_AVS0
depends on ARCH_K3 && SPL_DM_REGULATOR
bool "AVS class 0 support for K3 devices"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f7422c8e95a..dc5eb3af19c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress_config.o
obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
obj-$(CONFIG_JZ4780_EFUSE) += jz4780_efuse.o
obj-$(CONFIG_MICROCHIP_FLEXCOM) += microchip_flexcom.o
+obj-$(CONFIG_MPFS_SYSCONTROLLER) += mpfs_syscontroller.o
obj-$(CONFIG_K3_AVS0) += k3_avs.o
obj-$(CONFIG_ESM_K3) += k3_esm.o
obj-$(CONFIG_K3_BIST) += k3_bist.o
diff --git a/drivers/misc/mpfs_syscontroller.c b/drivers/misc/mpfs_syscontroller.c
new file mode 100644
index 00000000000..41e80815ab5
--- /dev/null
+++ b/drivers/misc/mpfs_syscontroller.c
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Microchip's PolarFire SoC (MPFS) System Controller Driver
+ *
+ * Copyright (C) 2024 Microchip Technology Inc. All rights reserved.
+ *
+ * Author: Jamie Gibbons <jamie.gibbons@microchip.com>
+ *
+ */
+
+#include <asm/system.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <env.h>
+#include <errno.h>
+#include <linux/compat.h>
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <log.h>
+#include <mailbox.h>
+#include <misc.h>
+#include <mpfs-mailbox.h>
+
+/* Descriptor table */
+#define CMD_OPCODE 0x0u
+#define CMD_DATA_SIZE 0U
+#define CMD_DATA NULL
+#define MBOX_OFFSET 0x0
+#define RESP_OFFSET 0x0
+#define RESP_BYTES 16U
+
+/**
+ * struct mpfs_syscontroller_priv - Structure representing System Controller data.
+ * @chan: Mailbox channel
+ * @c: Completion signal
+ */
+struct mpfs_syscontroller_priv {
+ struct mbox_chan chan;
+ struct completion c;
+};
+
+/**
+ * mpfs_syscontroller_run_service() - Run the MPFS system service
+ * @sys_controller: corresponding MPFS system service device
+ * @msg: Message to send
+ *
+ * Return: 0 if all goes good, else appropriate error message.
+ */
+int mpfs_syscontroller_run_service(struct mpfs_syscontroller_priv *sys_controller, struct mpfs_mss_msg *msg)
+{
+ int ret;
+
+ reinit_completion(&sys_controller->c);
+
+ /* Run the System Service Request */
+ ret = mbox_send(&sys_controller->chan, msg);
+ if (ret < 0)
+ dev_warn(sys_controller->chan.dev, "MPFS sys controller service timeout\n");
+
+ debug("%s: Service successful %s\n",
+ __func__, sys_controller->chan.dev->name);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mpfs_syscontroller_run_service);
+
+/**
+ * mpfs_syscontroller_read_sernum() - Use system service to read the device serial number
+ * @sys_serv_priv: system service private data
+ * @device_serial_number: device serial number
+ *
+ * Return: 0 if all went ok, else return appropriate error
+ */
+int mpfs_syscontroller_read_sernum(struct mpfs_sys_serv *sys_serv_priv, u8 *device_serial_number)
+{
+ unsigned long timeoutsecs = 300;
+ int ret;
+
+ struct mpfs_mss_response response = {
+ .resp_status = 0U,
+ .resp_msg = (u32 *)device_serial_number,
+ .resp_size = RESP_BYTES};
+ struct mpfs_mss_msg msg = {
+ .cmd_opcode = CMD_OPCODE,
+ .cmd_data_size = CMD_DATA_SIZE,
+ .response = &response,
+ .cmd_data = CMD_DATA,
+ .mbox_offset = MBOX_OFFSET,
+ .resp_offset = RESP_OFFSET};
+
+ ret = mpfs_syscontroller_run_service(sys_serv_priv->sys_controller, &msg);
+ if (ret) {
+ dev_err(sys_serv_priv->sys_controller->chan.dev, "Service failed: %d, abort\n", ret);
+ return ret;
+ }
+
+ /* Receive the response */
+ ret = mbox_recv(&sys_serv_priv->sys_controller->chan, &msg, timeoutsecs);
+ if (ret) {
+ dev_err(sys_serv_priv->sys_controller->chan.dev, "Service failed: %d, abort. Failure: %u\n", ret, msg.response->resp_status);
+ return ret;
+ }
+
+ debug("%s: Read successful %s\n",
+ __func__, sys_serv_priv->sys_controller->chan.dev->name);
+
+ return 0;
+}
+EXPORT_SYMBOL(mpfs_syscontroller_read_sernum);
+
+static int mpfs_syscontroller_probe(struct udevice *dev)
+{
+ struct mpfs_syscontroller_priv *sys_controller = dev_get_priv(dev);
+ int ret;
+
+ ret = mbox_get_by_index(dev, 0, &sys_controller->chan);
+ if (ret) {
+ dev_err(dev, "%s: Acquiring mailbox channel failed. ret = %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ init_completion(&sys_controller->c);
+ dev_info(dev, "Registered MPFS system controller\n");
+
+ return 0;
+}
+
+static const struct udevice_id mpfs_syscontroller_ids[] = {
+ { .compatible = "microchip,mpfs-sys-controller" },
+ { }
+};
+
+struct mpfs_syscontroller_priv *mpfs_syscontroller_get(struct udevice *dev)
+{
+ struct mpfs_syscontroller_priv *sys_controller;
+
+ sys_controller = dev_get_priv(dev);
+ if (!sys_controller) {
+ debug("%s: MPFS system controller found but could not register as a sub device %p\n",
+ __func__, sys_controller);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ return sys_controller;
+}
+EXPORT_SYMBOL(mpfs_syscontroller_get);
+
+U_BOOT_DRIVER(mpfs_syscontroller) = {
+ .name = "mpfs_syscontroller",
+ .id = UCLASS_MISC,
+ .of_match = mpfs_syscontroller_ids,
+ .probe = mpfs_syscontroller_probe,
+ .priv_auto = sizeof(struct mpfs_syscontroller_priv),
+};
diff --git a/drivers/phy/qcom/phy-qcom-snps-eusb2.c b/drivers/phy/qcom/phy-qcom-snps-eusb2.c
index b2655ac007c..28502c46f67 100644
--- a/drivers/phy/qcom/phy-qcom-snps-eusb2.c
+++ b/drivers/phy/qcom/phy-qcom-snps-eusb2.c
@@ -331,8 +331,9 @@ static int qcom_snps_eusb2_phy_probe(struct udevice *dev)
qcom_snps_eusb2->ref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(qcom_snps_eusb2->ref_clk)) {
+ ret = PTR_ERR(qcom_snps_eusb2->ref_clk);
printf("%s: failed to get ref clk %d\n", __func__, ret);
- return PTR_ERR(qcom_snps_eusb2->ref_clk);
+ return ret;
}
ret = reset_get_bulk(dev, &qcom_snps_eusb2->resets);
diff --git a/drivers/pinctrl/qcom/pinctrl-sa8775p.c b/drivers/pinctrl/qcom/pinctrl-sa8775p.c
index cb2496ff1fb..d4acae15d55 100644
--- a/drivers/pinctrl/qcom/pinctrl-sa8775p.c
+++ b/drivers/pinctrl/qcom/pinctrl-sa8775p.c
@@ -516,7 +516,9 @@ static const char *sa8775p_get_function_name(struct udevice *dev,
static const char *sa8775p_get_pin_name(struct udevice *dev,
unsigned int selector)
{
- if (selector >= 149 && selector <= 155)
+ if (selector > 153)
+ strcpy(pin_name, "unknown");
+ else if (selector >= 149)
snprintf(pin_name, MAX_PIN_NAME_LEN,
msm_special_pins_data[selector - 149].name);
else
diff --git a/drivers/pinctrl/qcom/pinctrl-sdm845.c b/drivers/pinctrl/qcom/pinctrl-sdm845.c
index 3f55fc81c8e..24b42e94c7a 100644
--- a/drivers/pinctrl/qcom/pinctrl-sdm845.c
+++ b/drivers/pinctrl/qcom/pinctrl-sdm845.c
@@ -72,7 +72,7 @@ static const char *sdm845_get_pin_name(struct udevice *dev,
"sdc2_data",
};
- if (selector >= 150 && selector <= 154)
+ if (selector >= 150 && selector <= 153)
snprintf(pin_name, MAX_PIN_NAME_LEN, special_pins_names[selector - 150]);
else
snprintf(pin_name, MAX_PIN_NAME_LEN, "gpio%u", selector);
diff --git a/drivers/serial/serial_msm_geni.c b/drivers/serial/serial_msm_geni.c
index cb6c09fdd09..0eb90f82a34 100644
--- a/drivers/serial/serial_msm_geni.c
+++ b/drivers/serial/serial_msm_geni.c
@@ -252,6 +252,10 @@ static int msm_serial_setbrg(struct udevice *dev, int baud)
priv->baud = baud;
clk_rate = get_clk_div_rate(baud, priv->oversampling, &clk_div);
+ if (!clk_rate) {
+ pr_err("%s: Couldn't get clock division rate\n", __func__);
+ return -EINVAL;
+ }
ret = geni_serial_set_clock_rate(dev, clk_rate);
if (ret < 0) {
pr_err("%s: Couldn't set clock rate: %d\n", __func__, ret);
@@ -284,23 +288,19 @@ static bool qcom_geni_serial_poll_bit(const struct udevice *dev, int offset,
unsigned int tx_fifo_depth;
unsigned int tx_fifo_width;
unsigned int fifo_bits;
- unsigned long timeout_us = 10000;
-
- baud = 115200;
-
- if (priv) {
- baud = priv->baud;
- if (!baud)
- baud = 115200;
- tx_fifo_depth = geni_se_get_tx_fifo_depth(priv->base);
- tx_fifo_width = geni_se_get_tx_fifo_width(priv->base);
- fifo_bits = tx_fifo_depth * tx_fifo_width;
- /*
- * Total polling iterations based on FIFO worth of bytes to be
- * sent at current baud. Add a little fluff to the wait.
- */
- timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500;
- }
+ unsigned long timeout_us;
+
+ baud = priv->baud;
+ if (!baud)
+ baud = 115200;
+ tx_fifo_depth = geni_se_get_tx_fifo_depth(priv->base);
+ tx_fifo_width = geni_se_get_tx_fifo_width(priv->base);
+ fifo_bits = tx_fifo_depth * tx_fifo_width;
+ /*
+ * Total polling iterations based on FIFO worth of bytes to be
+ * sent at current baud. Add a little fluff to the wait.
+ */
+ timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500;
timeout_us = DIV_ROUND_UP(timeout_us, 10) * 10;
while (timeout_us) {