This pull request contains Broadcom ARM/ARM64/MIPS SoCs drivers changes
for 5.3, please pull the following: - Markus provides a set of updates to the DPFE driver to support a new revision of the API to the firmware (version 3) and provides minor fixes about how the MR4-8 words are read for LPDDR4 devices - Florian removes a print of a virtual address in brcmstb_gisb.c -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEm+Rq3+YGJdiR9yuFh9CWnEQHBwQFAl0AZj0ACgkQh9CWnEQH BwQHpQ//ZeW9+W6GHfY1bBhBQSuCH8V0oPv3Js73yESOBSwTvn59Io6A3XS9XCuU I/j/rYI6hMiWpIpudPf92fOxI1+IgqIF6JE93MHQRgAdGHuHBxOfDA4cdGXcnUfw Qk+j33mwf9toX+rK3dlfTuNny6ic0cpAV4OPMhB37jgf+LtiY++JhFEkrYJzpdpk aTvar62yZr8hzTLIp69aKkf9pGy7h9DXBdHaU6iGNB7/HXeadN/qW4/cDXSQXcKi pNIwByABXh8ZOJVfRCK4nq+dYZSdEkiLRXRz/SH/czwQFAsqkH3FYmWiLRQxfFny XehOSjn5YJWX6mE6VzgqwtmDIdkqlmZS0Nu+E6zeWwDb28s8aHxESktps4aJcd18 jz3nl66n07SrkhRJGHd3TRvOiYJUr7TfcdqSxdm69e2uoy1zESpdoyA/5U691js0 gSRpsJb9nfGK3OlGjLcKyHkIhq6oiTbGZOp9hWNz8P/76wqak50DiS8CQx+HEqLb kanZvv+vf+bvDEHLkUXVRGhH4vuK7cXkkm0MjovdYqXDiM7hK1otv3UbD8rN6Gzv qF0AH2vH7fbi0w7Q+Bb0nGnct1qMhcUWUavNdjbWNgQe4fOXvm1uH/VujLSjaJ8Q 1HxB86RMnc1RnvpnFPk9gxIJj5cTrSx9n83SIGvz2F4EFYeK1zM= =Gw/Z -----END PGP SIGNATURE----- Merge tag 'arm-soc/for-5.3/drivers' of https://github.com/Broadcom/stblinux into arm/drivers This pull request contains Broadcom ARM/ARM64/MIPS SoCs drivers changes for 5.3, please pull the following: - Markus provides a set of updates to the DPFE driver to support a new revision of the API to the firmware (version 3) and provides minor fixes about how the MR4-8 words are read for LPDDR4 devices - Florian removes a print of a virtual address in brcmstb_gisb.c * tag 'arm-soc/for-5.3/drivers' of https://github.com/Broadcom/stblinux: memory: brcmstb: dpfe: introduce DPFE API v3 memory: brcmstb: dpfe: prepare for API-dependent sysfs attributes memory: brcmstb: dpfe: prepare support for multiple API versions memory: brcmstb: dpfe: wait for DCPU to be ready memory: brcmstb: dpfe: report firmware loading error memory: brcmstb: dpfe: remove unused code and fix formatting bus: brcmstb_gisb: Remove print of base address memory: brcmstb: dpfe: use byte 3 of registers MR4-MR8 memory: brcmstb: dpfe: optimize generic_show() memory: brcmstb: dpfe: use msleep() over udelay() Signed-off-by: Olof Johansson <olof@lixom.net>alistair/sunxi64-5.4-dsi
commit
426356392c
|
@ -399,8 +399,8 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
|
||||||
&gisb_panic_notifier);
|
&gisb_panic_notifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n",
|
dev_info(&pdev->dev, "registered irqs: %d, %d\n",
|
||||||
gdev->base, timeout_irq, tea_irq);
|
timeout_irq, tea_irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,10 +35,10 @@
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
#define DRVNAME "brcmstb-dpfe"
|
#define DRVNAME "brcmstb-dpfe"
|
||||||
#define FIRMWARE_NAME "dpfe.bin"
|
|
||||||
|
|
||||||
/* DCPU register offsets */
|
/* DCPU register offsets */
|
||||||
#define REG_DCPU_RESET 0x0
|
#define REG_DCPU_RESET 0x0
|
||||||
|
@ -61,6 +61,7 @@
|
||||||
#define DRAM_INFO_MR4 0x4
|
#define DRAM_INFO_MR4 0x4
|
||||||
#define DRAM_INFO_ERROR 0x8
|
#define DRAM_INFO_ERROR 0x8
|
||||||
#define DRAM_INFO_MR4_MASK 0xff
|
#define DRAM_INFO_MR4_MASK 0xff
|
||||||
|
#define DRAM_INFO_MR4_SHIFT 24 /* We need to look at byte 3 */
|
||||||
|
|
||||||
/* DRAM MR4 Offsets & Masks */
|
/* DRAM MR4 Offsets & Masks */
|
||||||
#define DRAM_MR4_REFRESH 0x0 /* Refresh rate */
|
#define DRAM_MR4_REFRESH 0x0 /* Refresh rate */
|
||||||
|
@ -75,13 +76,23 @@
|
||||||
#define DRAM_MR4_TH_OFFS_MASK 0x3
|
#define DRAM_MR4_TH_OFFS_MASK 0x3
|
||||||
#define DRAM_MR4_TUF_MASK 0x1
|
#define DRAM_MR4_TUF_MASK 0x1
|
||||||
|
|
||||||
/* DRAM Vendor Offsets & Masks */
|
/* DRAM Vendor Offsets & Masks (API v2) */
|
||||||
#define DRAM_VENDOR_MR5 0x0
|
#define DRAM_VENDOR_MR5 0x0
|
||||||
#define DRAM_VENDOR_MR6 0x4
|
#define DRAM_VENDOR_MR6 0x4
|
||||||
#define DRAM_VENDOR_MR7 0x8
|
#define DRAM_VENDOR_MR7 0x8
|
||||||
#define DRAM_VENDOR_MR8 0xc
|
#define DRAM_VENDOR_MR8 0xc
|
||||||
#define DRAM_VENDOR_ERROR 0x10
|
#define DRAM_VENDOR_ERROR 0x10
|
||||||
#define DRAM_VENDOR_MASK 0xff
|
#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 */
|
/* Reset register bits & masks */
|
||||||
#define DCPU_RESET_SHIFT 0x0
|
#define DCPU_RESET_SHIFT 0x0
|
||||||
|
@ -111,7 +122,7 @@
|
||||||
#define DPFE_MSG_TYPE_COMMAND 1
|
#define DPFE_MSG_TYPE_COMMAND 1
|
||||||
#define DPFE_MSG_TYPE_RESPONSE 2
|
#define DPFE_MSG_TYPE_RESPONSE 2
|
||||||
|
|
||||||
#define DELAY_LOOP_MAX 200000
|
#define DELAY_LOOP_MAX 1000
|
||||||
|
|
||||||
enum dpfe_msg_fields {
|
enum dpfe_msg_fields {
|
||||||
MSG_HEADER,
|
MSG_HEADER,
|
||||||
|
@ -119,7 +130,7 @@ enum dpfe_msg_fields {
|
||||||
MSG_ARG_COUNT,
|
MSG_ARG_COUNT,
|
||||||
MSG_ARG0,
|
MSG_ARG0,
|
||||||
MSG_CHKSUM,
|
MSG_CHKSUM,
|
||||||
MSG_FIELD_MAX /* Last entry */
|
MSG_FIELD_MAX = 16 /* Max number of arguments */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum dpfe_commands {
|
enum dpfe_commands {
|
||||||
|
@ -129,14 +140,6 @@ enum dpfe_commands {
|
||||||
DPFE_CMD_MAX /* Last entry */
|
DPFE_CMD_MAX /* Last entry */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dpfe_msg {
|
|
||||||
u32 header;
|
|
||||||
u32 command;
|
|
||||||
u32 arg_count;
|
|
||||||
u32 arg0;
|
|
||||||
u32 chksum; /* This is the sum of all other entries. */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Format of the binary firmware file:
|
* Format of the binary firmware file:
|
||||||
*
|
*
|
||||||
|
@ -170,12 +173,21 @@ struct init_data {
|
||||||
bool is_big_endian;
|
bool is_big_endian;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* API version and corresponding commands */
|
||||||
|
struct dpfe_api {
|
||||||
|
int version;
|
||||||
|
const char *fw_name;
|
||||||
|
const struct attribute_group **sysfs_attrs;
|
||||||
|
u32 command[DPFE_CMD_MAX][MSG_FIELD_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
/* Things we need for as long as we are active. */
|
/* Things we need for as long as we are active. */
|
||||||
struct private_data {
|
struct private_data {
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
void __iomem *dmem;
|
void __iomem *dmem;
|
||||||
void __iomem *imem;
|
void __iomem *imem;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
const struct dpfe_api *dpfe_api;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -184,28 +196,99 @@ static const char *error_text[] = {
|
||||||
"Incorrect checksum", "Malformed command", "Timed out",
|
"Incorrect checksum", "Malformed command", "Timed out",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* List of supported firmware commands */
|
/*
|
||||||
static const u32 dpfe_commands[DPFE_CMD_MAX][MSG_FIELD_MAX] = {
|
* Forward declaration of our sysfs attribute functions, so we can declare the
|
||||||
[DPFE_CMD_GET_INFO] = {
|
* attribute data structures early.
|
||||||
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
*/
|
||||||
[MSG_COMMAND] = 1,
|
static ssize_t show_info(struct device *, struct device_attribute *, char *);
|
||||||
[MSG_ARG_COUNT] = 1,
|
static ssize_t show_refresh(struct device *, struct device_attribute *, char *);
|
||||||
[MSG_ARG0] = 1,
|
static ssize_t store_refresh(struct device *, struct device_attribute *,
|
||||||
[MSG_CHKSUM] = 4,
|
const char *, size_t);
|
||||||
},
|
static ssize_t show_vendor(struct device *, struct device_attribute *, char *);
|
||||||
[DPFE_CMD_GET_REFRESH] = {
|
static ssize_t show_dram(struct device *, struct device_attribute *, char *);
|
||||||
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
|
||||||
[MSG_COMMAND] = 2,
|
/*
|
||||||
[MSG_ARG_COUNT] = 1,
|
* Declare our attributes early, so they can be referenced in the API data
|
||||||
[MSG_ARG0] = 1,
|
* structure. We need to do this, because the attributes depend on the API
|
||||||
[MSG_CHKSUM] = 5,
|
* version.
|
||||||
},
|
*/
|
||||||
[DPFE_CMD_GET_VENDOR] = {
|
static DEVICE_ATTR(dpfe_info, 0444, show_info, NULL);
|
||||||
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
static DEVICE_ATTR(dpfe_refresh, 0644, show_refresh, store_refresh);
|
||||||
[MSG_COMMAND] = 2,
|
static DEVICE_ATTR(dpfe_vendor, 0444, show_vendor, NULL);
|
||||||
[MSG_ARG_COUNT] = 1,
|
static DEVICE_ATTR(dpfe_dram, 0444, show_dram, NULL);
|
||||||
[MSG_ARG0] = 2,
|
|
||||||
[MSG_CHKSUM] = 6,
|
/* API v2 sysfs attributes */
|
||||||
|
static struct attribute *dpfe_v2_attrs[] = {
|
||||||
|
&dev_attr_dpfe_info.attr,
|
||||||
|
&dev_attr_dpfe_refresh.attr,
|
||||||
|
&dev_attr_dpfe_vendor.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
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,
|
||||||
|
.fw_name = "dpfe.bin",
|
||||||
|
.sysfs_attrs = dpfe_v2_groups,
|
||||||
|
.command = {
|
||||||
|
[DPFE_CMD_GET_INFO] = {
|
||||||
|
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
||||||
|
[MSG_COMMAND] = 1,
|
||||||
|
[MSG_ARG_COUNT] = 1,
|
||||||
|
[MSG_ARG0] = 1,
|
||||||
|
[MSG_CHKSUM] = 4,
|
||||||
|
},
|
||||||
|
[DPFE_CMD_GET_REFRESH] = {
|
||||||
|
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
||||||
|
[MSG_COMMAND] = 2,
|
||||||
|
[MSG_ARG_COUNT] = 1,
|
||||||
|
[MSG_ARG0] = 1,
|
||||||
|
[MSG_CHKSUM] = 5,
|
||||||
|
},
|
||||||
|
[DPFE_CMD_GET_VENDOR] = {
|
||||||
|
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
|
||||||
|
[MSG_COMMAND] = 2,
|
||||||
|
[MSG_ARG_COUNT] = 1,
|
||||||
|
[MSG_ARG0] = 2,
|
||||||
|
[MSG_CHKSUM] = 6,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -250,13 +333,13 @@ static void __enable_dcpu(void __iomem *regs)
|
||||||
writel_relaxed(val, regs + REG_DCPU_RESET);
|
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 sum = 0;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
/* Don't include the last field in the checksum. */
|
/* 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];
|
sum += msg[i];
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
|
@ -269,6 +352,11 @@ static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
|
||||||
unsigned int offset;
|
unsigned int offset;
|
||||||
void __iomem *ptr = NULL;
|
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;
|
msg_type = (response >> DRAM_MSG_TYPE_OFFSET) & DRAM_MSG_TYPE_MASK;
|
||||||
offset = (response >> DRAM_MSG_ADDR_OFFSET) & DRAM_MSG_ADDR_MASK;
|
offset = (response >> DRAM_MSG_ADDR_OFFSET) & DRAM_MSG_ADDR_MASK;
|
||||||
|
|
||||||
|
@ -296,12 +384,25 @@ static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
|
||||||
return ptr;
|
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,
|
static int __send_command(struct private_data *priv, unsigned int cmd,
|
||||||
u32 result[])
|
u32 result[])
|
||||||
{
|
{
|
||||||
const u32 *msg = dpfe_commands[cmd];
|
const u32 *msg = priv->dpfe_api->command[cmd];
|
||||||
void __iomem *regs = priv->regs;
|
void __iomem *regs = priv->regs;
|
||||||
unsigned int i, chksum;
|
unsigned int i, chksum, chksum_idx;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
u32 resp;
|
u32 resp;
|
||||||
|
|
||||||
|
@ -310,6 +411,18 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
|
||||||
|
|
||||||
mutex_lock(&priv->lock);
|
mutex_lock(&priv->lock);
|
||||||
|
|
||||||
|
/* Wait for DCPU to become ready */
|
||||||
|
for (i = 0; i < DELAY_LOOP_MAX; i++) {
|
||||||
|
resp = readl_relaxed(regs + REG_TO_HOST_MBOX);
|
||||||
|
if (resp == 0)
|
||||||
|
break;
|
||||||
|
msleep(1);
|
||||||
|
}
|
||||||
|
if (resp != 0) {
|
||||||
|
mutex_unlock(&priv->lock);
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
/* Write command and arguments to message area */
|
/* Write command and arguments to message area */
|
||||||
for (i = 0; i < MSG_FIELD_MAX; i++)
|
for (i = 0; i < MSG_FIELD_MAX; i++)
|
||||||
writel_relaxed(msg[i], regs + DCPU_MSG_RAM(i));
|
writel_relaxed(msg[i], regs + DCPU_MSG_RAM(i));
|
||||||
|
@ -323,7 +436,7 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
|
||||||
resp = readl_relaxed(regs + REG_TO_HOST_MBOX);
|
resp = readl_relaxed(regs + REG_TO_HOST_MBOX);
|
||||||
if (resp > 0)
|
if (resp > 0)
|
||||||
break;
|
break;
|
||||||
udelay(5);
|
msleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == DELAY_LOOP_MAX) {
|
if (i == DELAY_LOOP_MAX) {
|
||||||
|
@ -333,10 +446,11 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
|
||||||
/* Read response data */
|
/* Read response data */
|
||||||
for (i = 0; i < MSG_FIELD_MAX; i++)
|
for (i = 0; i < MSG_FIELD_MAX; i++)
|
||||||
result[i] = readl_relaxed(regs + DCPU_MSG_RAM(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 */
|
/* Tell DCPU we are done */
|
||||||
writel_relaxed(0, regs + REG_TO_HOST_MBOX);
|
__finalize_command(priv);
|
||||||
|
|
||||||
mutex_unlock(&priv->lock);
|
mutex_unlock(&priv->lock);
|
||||||
|
|
||||||
|
@ -344,8 +458,8 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* Verify response */
|
/* Verify response */
|
||||||
chksum = get_msg_chksum(result);
|
chksum = get_msg_chksum(result, chksum_idx);
|
||||||
if (chksum != result[MSG_CHKSUM])
|
if (chksum != result[chksum_idx])
|
||||||
resp = DCPU_RET_ERR_CHKSUM;
|
resp = DCPU_RET_ERR_CHKSUM;
|
||||||
|
|
||||||
if (resp != DCPU_RET_SUCCESS) {
|
if (resp != DCPU_RET_SUCCESS) {
|
||||||
|
@ -486,7 +600,15 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = request_firmware(&fw, FIRMWARE_NAME, dev);
|
/*
|
||||||
|
* If the firmware filename is NULL it means the boot firmware has to
|
||||||
|
* download the DCPU firmware for us. If that didn't work, we have to
|
||||||
|
* bail, since downloading it ourselves wouldn't work either.
|
||||||
|
*/
|
||||||
|
if (!priv->dpfe_api->fw_name)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
ret = request_firmware(&fw, priv->dpfe_api->fw_name, dev);
|
||||||
/* request_firmware() prints its own error messages. */
|
/* request_firmware() prints its own error messages. */
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -527,12 +649,10 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t generic_show(unsigned int command, u32 response[],
|
static ssize_t generic_show(unsigned int command, u32 response[],
|
||||||
struct device *dev, char *buf)
|
struct private_data *priv, char *buf)
|
||||||
{
|
{
|
||||||
struct private_data *priv;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
priv = dev_get_drvdata(dev);
|
|
||||||
if (!priv)
|
if (!priv)
|
||||||
return sprintf(buf, "ERROR: driver private data not set\n");
|
return sprintf(buf, "ERROR: driver private data not set\n");
|
||||||
|
|
||||||
|
@ -547,10 +667,12 @@ static ssize_t show_info(struct device *dev, struct device_attribute *devattr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
u32 response[MSG_FIELD_MAX];
|
u32 response[MSG_FIELD_MAX];
|
||||||
|
struct private_data *priv;
|
||||||
unsigned int info;
|
unsigned int info;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
ret = generic_show(DPFE_CMD_GET_INFO, response, dev, buf);
|
priv = dev_get_drvdata(dev);
|
||||||
|
ret = generic_show(DPFE_CMD_GET_INFO, response, priv, buf);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -573,17 +695,17 @@ static ssize_t show_refresh(struct device *dev,
|
||||||
u32 mr4;
|
u32 mr4;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
ret = generic_show(DPFE_CMD_GET_REFRESH, response, dev, buf);
|
priv = dev_get_drvdata(dev);
|
||||||
|
ret = generic_show(DPFE_CMD_GET_REFRESH, response, priv, buf);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
priv = dev_get_drvdata(dev);
|
|
||||||
|
|
||||||
info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret);
|
info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret);
|
||||||
if (!info)
|
if (!info)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
mr4 = readl_relaxed(info + DRAM_INFO_MR4) & DRAM_INFO_MR4_MASK;
|
mr4 = (readl_relaxed(info + DRAM_INFO_MR4) >> DRAM_INFO_MR4_SHIFT) &
|
||||||
|
DRAM_INFO_MR4_MASK;
|
||||||
|
|
||||||
refresh = (mr4 >> DRAM_MR4_REFRESH) & DRAM_MR4_REFRESH_MASK;
|
refresh = (mr4 >> DRAM_MR4_REFRESH) & DRAM_MR4_REFRESH_MASK;
|
||||||
sr_abort = (mr4 >> DRAM_MR4_SR_ABORT) & DRAM_MR4_SR_ABORT_MASK;
|
sr_abort = (mr4 >> DRAM_MR4_SR_ABORT) & DRAM_MR4_SR_ABORT_MASK;
|
||||||
|
@ -610,7 +732,6 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
priv = dev_get_drvdata(dev);
|
priv = dev_get_drvdata(dev);
|
||||||
|
|
||||||
ret = __send_command(priv, DPFE_CMD_GET_REFRESH, response);
|
ret = __send_command(priv, DPFE_CMD_GET_REFRESH, response);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -625,30 +746,58 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr,
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr,
|
static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
u32 response[MSG_FIELD_MAX];
|
u32 response[MSG_FIELD_MAX];
|
||||||
struct private_data *priv;
|
struct private_data *priv;
|
||||||
void __iomem *info;
|
void __iomem *info;
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
u32 mr5, mr6, mr7, mr8, err;
|
||||||
ret = generic_show(DPFE_CMD_GET_VENDOR, response, dev, buf);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
priv = dev_get_drvdata(dev);
|
priv = dev_get_drvdata(dev);
|
||||||
|
ret = generic_show(DPFE_CMD_GET_VENDOR, response, priv, buf);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret);
|
info = get_msg_ptr(priv, response[MSG_ARG0], buf, &ret);
|
||||||
if (!info)
|
if (!info)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
return sprintf(buf, "%#x %#x %#x %#x %#x\n",
|
mr5 = (readl_relaxed(info + DRAM_VENDOR_MR5) >> DRAM_VENDOR_SHIFT) &
|
||||||
readl_relaxed(info + DRAM_VENDOR_MR5) & DRAM_VENDOR_MASK,
|
DRAM_VENDOR_MASK;
|
||||||
readl_relaxed(info + DRAM_VENDOR_MR6) & DRAM_VENDOR_MASK,
|
mr6 = (readl_relaxed(info + DRAM_VENDOR_MR6) >> DRAM_VENDOR_SHIFT) &
|
||||||
readl_relaxed(info + DRAM_VENDOR_MR7) & DRAM_VENDOR_MASK,
|
DRAM_VENDOR_MASK;
|
||||||
readl_relaxed(info + DRAM_VENDOR_MR8) & DRAM_VENDOR_MASK,
|
mr7 = (readl_relaxed(info + DRAM_VENDOR_MR7) >> DRAM_VENDOR_SHIFT) &
|
||||||
readl_relaxed(info + DRAM_VENDOR_ERROR) &
|
DRAM_VENDOR_MASK;
|
||||||
DRAM_VENDOR_MASK);
|
mr8 = (readl_relaxed(info + DRAM_VENDOR_MR8) >> DRAM_VENDOR_SHIFT) &
|
||||||
|
DRAM_VENDOR_MASK;
|
||||||
|
err = readl_relaxed(info + DRAM_VENDOR_ERROR) & DRAM_VENDOR_MASK;
|
||||||
|
|
||||||
|
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)
|
static int brcmstb_dpfe_resume(struct platform_device *pdev)
|
||||||
|
@ -658,17 +807,6 @@ static int brcmstb_dpfe_resume(struct platform_device *pdev)
|
||||||
return brcmstb_dpfe_download_firmware(pdev, &init);
|
return brcmstb_dpfe_download_firmware(pdev, &init);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 struct attribute *dpfe_attrs[] = {
|
|
||||||
&dev_attr_dpfe_info.attr,
|
|
||||||
&dev_attr_dpfe_refresh.attr,
|
|
||||||
&dev_attr_dpfe_vendor.attr,
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
ATTRIBUTE_GROUPS(dpfe);
|
|
||||||
|
|
||||||
static int brcmstb_dpfe_probe(struct platform_device *pdev)
|
static int brcmstb_dpfe_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
|
@ -705,26 +843,47 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = brcmstb_dpfe_download_firmware(pdev, &init);
|
priv->dpfe_api = of_device_get_match_data(dev);
|
||||||
if (ret)
|
if (unlikely(!priv->dpfe_api)) {
|
||||||
return ret;
|
/*
|
||||||
|
* It should be impossible to end up here, but to be safe we
|
||||||
|
* check anyway.
|
||||||
|
*/
|
||||||
|
dev_err(dev, "Couldn't determine API\n");
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
ret = sysfs_create_groups(&pdev->dev.kobj, dpfe_groups);
|
ret = brcmstb_dpfe_download_firmware(pdev, &init);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Couldn't download firmware -- %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sysfs_create_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
dev_info(dev, "registered.\n");
|
dev_info(dev, "registered with API v%d.\n",
|
||||||
|
priv->dpfe_api->version);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int brcmstb_dpfe_remove(struct platform_device *pdev)
|
static int brcmstb_dpfe_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
sysfs_remove_groups(&pdev->dev.kobj, dpfe_groups);
|
struct private_data *priv = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
sysfs_remove_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id brcmstb_dpfe_of_match[] = {
|
static const struct of_device_id brcmstb_dpfe_of_match[] = {
|
||||||
{ .compatible = "brcm,dpfe-cpu", },
|
/* 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);
|
MODULE_DEVICE_TABLE(of, brcmstb_dpfe_of_match);
|
||||||
|
|
Loading…
Reference in New Issue