[PATCH 6/6] memory: brcmstb: dpfe: introduce DPFE API v3

From: Markus Mayer
Date: Tue Apr 02 2019 - 19:07:45 EST


From: Markus Mayer <mmayer@xxxxxxxxxxxx>

Introduce code to handle DPFE API v3. We also change the driver to
default to v3 by default and use API v2 only for select chips.

Signed-off-by: Markus Mayer <mmayer@xxxxxxxxxxxx>
---
drivers/memory/brcmstb_dpfe.c | 114 +++++++++++++++++++++++++++++++---
1 file changed, 105 insertions(+), 9 deletions(-)

diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c
index 43a53246abb3..bc6bf263c859 100644
--- a/drivers/memory/brcmstb_dpfe.c
+++ b/drivers/memory/brcmstb_dpfe.c
@@ -76,7 +76,7 @@
#define DRAM_MR4_TH_OFFS_MASK 0x3
#define DRAM_MR4_TUF_MASK 0x1

-/* DRAM Vendor Offsets & Masks */
+/* DRAM Vendor Offsets & Masks (API v2) */
#define DRAM_VENDOR_MR5 0x0
#define DRAM_VENDOR_MR6 0x4
#define DRAM_VENDOR_MR7 0x8
@@ -85,6 +85,15 @@
#define DRAM_VENDOR_MASK 0xff
#define DRAM_VENDOR_SHIFT 24 /* We need to look at byte 3 */

+/* DRAM Information Offsets & Masks (API v3) */
+#define DRAM_DDR_INFO_MR4 0x0
+#define DRAM_DDR_INFO_MR5 0x4
+#define DRAM_DDR_INFO_MR6 0x8
+#define DRAM_DDR_INFO_MR7 0xc
+#define DRAM_DDR_INFO_MR8 0x10
+#define DRAM_DDR_INFO_ERROR 0x14
+#define DRAM_DDR_INFO_MASK 0xff
+
/* Reset register bits & masks */
#define DCPU_RESET_SHIFT 0x0
#define DCPU_RESET_MASK 0x1
@@ -121,7 +130,7 @@ enum dpfe_msg_fields {
MSG_ARG_COUNT,
MSG_ARG0,
MSG_CHKSUM,
- MSG_FIELD_MAX /* Last entry */
+ MSG_FIELD_MAX = 16 /* Max number of arguments */
};

enum dpfe_commands {
@@ -196,6 +205,7 @@ static ssize_t show_refresh(struct device *, struct device_attribute *, char *);
static ssize_t store_refresh(struct device *, struct device_attribute *,
const char *, size_t);
static ssize_t show_vendor(struct device *, struct device_attribute *, char *);
+static ssize_t show_dram(struct device *, struct device_attribute *, char *);

/*
* Declare our attributes early, so they can be referenced in the API data
@@ -205,6 +215,7 @@ static ssize_t show_vendor(struct device *, struct device_attribute *, char *);
static DEVICE_ATTR(dpfe_info, 0444, show_info, NULL);
static DEVICE_ATTR(dpfe_refresh, 0644, show_refresh, store_refresh);
static DEVICE_ATTR(dpfe_vendor, 0444, show_vendor, NULL);
+static DEVICE_ATTR(dpfe_dram, 0444, show_dram, NULL);

/* API v2 sysfs attributes */
static struct attribute *dpfe_v2_attrs[] = {
@@ -215,6 +226,14 @@ static struct attribute *dpfe_v2_attrs[] = {
};
ATTRIBUTE_GROUPS(dpfe_v2);

+/* API v3 sysfs attributes */
+static struct attribute *dpfe_v3_attrs[] = {
+ &dev_attr_dpfe_info.attr,
+ &dev_attr_dpfe_dram.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(dpfe_v3);
+
/* API v2 firmware commands */
static const struct dpfe_api dpfe_api_v2 = {
.version = 2,
@@ -245,6 +264,34 @@ static const struct dpfe_api dpfe_api_v2 = {
}
};

+/* API v3 firmware commands */
+static const struct dpfe_api dpfe_api_v3 = {
+ .version = 3,
+ .fw_name = NULL, /* We expect the firmware to have been downloaded! */
+ .sysfs_attrs = dpfe_v3_groups,
+ .command = {
+ [DPFE_CMD_GET_INFO] = {
+ [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
+ [MSG_COMMAND] = 0x0101,
+ [MSG_ARG_COUNT] = 1,
+ [MSG_ARG0] = 1,
+ [MSG_CHKSUM] = 0x104,
+ },
+ [DPFE_CMD_GET_REFRESH] = {
+ [MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
+ [MSG_COMMAND] = 0x0202,
+ [MSG_ARG_COUNT] = 0,
+ /*
+ * This is a bit ugly. Without arguments, the checksum
+ * follows right after the argument count and not at
+ * offset MSG_CHKSUM.
+ */
+ [MSG_ARG0] = 0x203,
+ },
+ /* There's no GET_VENDOR command in API v3. */
+ },
+};
+
static bool is_dcpu_enabled(void __iomem *regs)
{
u32 val;
@@ -286,13 +333,13 @@ static void __enable_dcpu(void __iomem *regs)
writel_relaxed(val, regs + REG_DCPU_RESET);
}

-static unsigned int get_msg_chksum(const u32 msg[])
+static unsigned int get_msg_chksum(const u32 msg[], unsigned int max)
{
unsigned int sum = 0;
unsigned int i;

/* Don't include the last field in the checksum. */
- for (i = 0; i < MSG_FIELD_MAX - 1; i++)
+ for (i = 0; i < max; i++)
sum += msg[i];

return sum;
@@ -305,6 +352,11 @@ static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
unsigned int offset;
void __iomem *ptr = NULL;

+ /* There is no need to use this function for API v3 or later. */
+ if (unlikely(priv->dpfe_api->version >= 3)) {
+ return NULL;
+ }
+
msg_type = (response >> DRAM_MSG_TYPE_OFFSET) & DRAM_MSG_TYPE_MASK;
offset = (response >> DRAM_MSG_ADDR_OFFSET) & DRAM_MSG_ADDR_MASK;

@@ -332,12 +384,25 @@ static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
return ptr;
}

+static void __finalize_command(struct private_data *priv)
+{
+ unsigned int release_mbox;
+
+ /*
+ * It depends on the API version which MBOX register we have to write to
+ * to signal we are done.
+ */
+ release_mbox = (priv->dpfe_api->version < 3)
+ ? REG_TO_HOST_MBOX : REG_TO_DCPU_MBOX;
+ writel_relaxed(0, priv->regs + release_mbox);
+}
+
static int __send_command(struct private_data *priv, unsigned int cmd,
u32 result[])
{
const u32 *msg = priv->dpfe_api->command[cmd];
void __iomem *regs = priv->regs;
- unsigned int i, chksum;
+ unsigned int i, chksum, chksum_idx;
int ret = 0;
u32 resp;

@@ -381,10 +446,11 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
/* Read response data */
for (i = 0; i < MSG_FIELD_MAX; i++)
result[i] = readl_relaxed(regs + DCPU_MSG_RAM(i));
+ chksum_idx = result[MSG_ARG_COUNT] + MSG_ARG_COUNT + 1;
}

/* Tell DCPU we are done */
- writel_relaxed(0, regs + REG_TO_HOST_MBOX);
+ __finalize_command(priv);

mutex_unlock(&priv->lock);

@@ -392,8 +458,8 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
return ret;

/* Verify response */
- chksum = get_msg_chksum(result);
- if (chksum != result[MSG_CHKSUM])
+ chksum = get_msg_chksum(result, chksum_idx);
+ if (chksum != result[chksum_idx])
resp = DCPU_RET_ERR_CHKSUM;

if (resp != DCPU_RET_SUCCESS) {
@@ -710,6 +776,30 @@ static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr,
return sprintf(buf, "%#x %#x %#x %#x %#x\n", mr5, mr6, mr7, mr8, err);
}

+static ssize_t show_dram(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ u32 response[MSG_FIELD_MAX];
+ struct private_data *priv;
+ ssize_t ret;
+ u32 mr4, mr5, mr6, mr7, mr8, err;
+
+ priv = dev_get_drvdata(dev);
+ ret = generic_show(DPFE_CMD_GET_REFRESH, response, priv, buf);
+ if (ret)
+ return ret;
+
+ mr4 = response[MSG_ARG0 + 0] & DRAM_INFO_MR4_MASK;
+ mr5 = response[MSG_ARG0 + 1] & DRAM_DDR_INFO_MASK;
+ mr6 = response[MSG_ARG0 + 2] & DRAM_DDR_INFO_MASK;
+ mr7 = response[MSG_ARG0 + 3] & DRAM_DDR_INFO_MASK;
+ mr8 = response[MSG_ARG0 + 4] & DRAM_DDR_INFO_MASK;
+ err = response[MSG_ARG0 + 5] & DRAM_DDR_INFO_MASK;
+
+ return sprintf(buf, "%#x %#x %#x %#x %#x %#x\n", mr4, mr5, mr6, mr7,
+ mr8, err);
+}
+
static int brcmstb_dpfe_resume(struct platform_device *pdev)
{
struct init_data init;
@@ -787,7 +877,13 @@ static int brcmstb_dpfe_remove(struct platform_device *pdev)
}

static const struct of_device_id brcmstb_dpfe_of_match[] = {
- { .compatible = "brcm,dpfe-cpu", .data = &dpfe_api_v2 },
+ /* Use legacy API v2 for a select number of chips */
+ { .compatible = "brcm,bcm7268-dpfe-cpu", .data = &dpfe_api_v2 },
+ { .compatible = "brcm,bcm7271-dpfe-cpu", .data = &dpfe_api_v2 },
+ { .compatible = "brcm,bcm7278-dpfe-cpu", .data = &dpfe_api_v2 },
+ { .compatible = "brcm,bcm7211-dpfe-cpu", .data = &dpfe_api_v2 },
+ /* API v3 is the default going forward */
+ { .compatible = "brcm,dpfe-cpu", .data = &dpfe_api_v3 },
{}
};
MODULE_DEVICE_TABLE(of, brcmstb_dpfe_of_match);
--
2.17.1