This pull request contains Broadcom ARM/ARM64/MIPS based SoCs drivers

updates for 5.5, please pull the following:
 
 - Markus updates the DPFE driver so as to support deferring the firmware
   loading process until the first sysfs attribute is accessed, in the
   process he does a bunch of cleanups and minor fixes
 
 - Florian adds support for the DPFE on 7211 which uses a "new style" API
   v2 and makes necessary changes along the way
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEm+Rq3+YGJdiR9yuFh9CWnEQHBwQFAl2wpXkACgkQh9CWnEQH
 BwQvtg//TR6lLmss+jJ99G91P2b+iHQPpXySzE6mxUcrqt4VG8gQNTchyK7g5Qrq
 ISw/KZ99f4c/MwWdEeNBkOmk5Uba//D8LoXdbHTUCSNmOtqMOz7vy5MfeZNHxHTT
 79RfO717hhj+4VHQPIhcpA5A/U9wl42WPVylZFEh0iXMv0lroGSS1CZBM8QFwAVY
 c7IgVaFj7tLxhm2jxixbvYUYT3ogUQcSLJCNe7RWgSYFMg5PN/J0LbpQNNbhMpXP
 pIA1qsAC0vV+enpxlDV2xi+RDl7mrkdEJav18j5KcZbfBX7f9wPO24s3yIrd96fp
 Irox/WRuiCII5LSYE35EF880n62WaNfGdErG0m+1ZF/DzIUUKcbt2JZGcOq1ANVK
 SUZloZTSKqDp2hn3f9GPK0re2aHB5EV8elRxS/5QXdL3LVdLJSFYceahow6DtLCY
 8jRCXMd5rZJVs6PjZxGl7PeHGiJ0JlCLjpYAUtD6jb7L3dnjR1XxVP9i5wBXj6Cu
 WJCbfbkyfXmst5+kH0TBqFSn11yxtzbXAboWDd6oocERdVQTncjhfAxhRf2pZe+C
 s6iJ4k+HzKInykAZHb/KK9OEDTawy26Z6wWsdMQObG0Hp5437PGC5R+IuoOZceHa
 uDeoHTYkJZG9ITDOG050kZDGzYvO4J6oOolXz4gcB7xn4XiZKCw=
 =rU3w
 -----END PGP SIGNATURE-----

Merge tag 'arm-soc/for-5.5/drivers' of https://github.com/Broadcom/stblinux into arm/drivers

This pull request contains Broadcom ARM/ARM64/MIPS based SoCs drivers
updates for 5.5, please pull the following:

- Markus updates the DPFE driver so as to support deferring the firmware
  loading process until the first sysfs attribute is accessed, in the
  process he does a bunch of cleanups and minor fixes

- Florian adds support for the DPFE on 7211 which uses a "new style" API
  v2 and makes necessary changes along the way

* tag 'arm-soc/for-5.5/drivers' of https://github.com/Broadcom/stblinux:
  memory: brcmstb: dpfe: Fixup API version/commands for 7211
  memory: brcmstb: dpfe: Compute checksum at __send_command() time
  memory: brcmstb: dpfe: support for deferred firmware download
  memory: brcmstb: dpfe: pass *priv as argument to brcmstb_dpfe_download_firmware()
  memory: brcmstb: dpfe: move init_data into brcmstb_dpfe_download_firmware()
  memory: brcmstb: dpfe: add locking around DCPU enable/disable
  memory: brcmstb: dpfe: initialize priv->dev
  memory: brcmstb: dpfe: rename struct private_data

Link: https://lore.kernel.org/r/20191023212814.30622-2-f.fainelli@gmail.com
Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
Olof Johansson 2019-10-23 20:00:48 -07:00
commit 3c1aa0c0cb
1 changed files with 101 additions and 63 deletions

View File

@ -127,7 +127,6 @@ enum dpfe_msg_fields {
MSG_COMMAND,
MSG_ARG_COUNT,
MSG_ARG0,
MSG_CHKSUM,
MSG_FIELD_MAX = 16 /* Max number of arguments */
};
@ -180,7 +179,7 @@ struct dpfe_api {
};
/* Things we need for as long as we are active. */
struct private_data {
struct brcmstb_dpfe_priv {
void __iomem *regs;
void __iomem *dmem;
void __iomem *imem;
@ -232,9 +231,13 @@ static struct attribute *dpfe_v3_attrs[] = {
};
ATTRIBUTE_GROUPS(dpfe_v3);
/* API v2 firmware commands */
static const struct dpfe_api dpfe_api_v2 = {
.version = 2,
/*
* Old API v2 firmware commands, as defined in the rev 0.61 specification, we
* use a version set to 1 to denote that it is not compatible with the new API
* v2 and onwards.
*/
static const struct dpfe_api dpfe_api_old_v2 = {
.version = 1,
.fw_name = "dpfe.bin",
.sysfs_attrs = dpfe_v2_groups,
.command = {
@ -243,21 +246,42 @@ static const struct dpfe_api dpfe_api_v2 = {
[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 v2 firmware commands, as defined in the rev 0.8 specification, named new
* v2 here
*/
static const struct dpfe_api dpfe_api_new_v2 = {
.version = 2,
.fw_name = NULL, /* We expect the firmware to have been downloaded! */
.sysfs_attrs = dpfe_v2_groups,
.command = {
[DPFE_CMD_GET_INFO] = {
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
[MSG_COMMAND] = 0x101,
},
[DPFE_CMD_GET_REFRESH] = {
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
[MSG_COMMAND] = 0x201,
},
[DPFE_CMD_GET_VENDOR] = {
[MSG_HEADER] = DPFE_MSG_TYPE_COMMAND,
[MSG_COMMAND] = 0x202,
},
}
};
@ -273,49 +297,51 @@ static const struct dpfe_api dpfe_api_v3 = {
[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)
static bool is_dcpu_enabled(struct brcmstb_dpfe_priv *priv)
{
u32 val;
val = readl_relaxed(regs + REG_DCPU_RESET);
mutex_lock(&priv->lock);
val = readl_relaxed(priv->regs + REG_DCPU_RESET);
mutex_unlock(&priv->lock);
return !(val & DCPU_RESET_MASK);
}
static void __disable_dcpu(void __iomem *regs)
static void __disable_dcpu(struct brcmstb_dpfe_priv *priv)
{
u32 val;
if (!is_dcpu_enabled(regs))
if (!is_dcpu_enabled(priv))
return;
mutex_lock(&priv->lock);
/* Put DCPU in reset if it's running. */
val = readl_relaxed(regs + REG_DCPU_RESET);
val = readl_relaxed(priv->regs + REG_DCPU_RESET);
val |= (1 << DCPU_RESET_SHIFT);
writel_relaxed(val, regs + REG_DCPU_RESET);
writel_relaxed(val, priv->regs + REG_DCPU_RESET);
mutex_unlock(&priv->lock);
}
static void __enable_dcpu(void __iomem *regs)
static void __enable_dcpu(struct brcmstb_dpfe_priv *priv)
{
void __iomem *regs = priv->regs;
u32 val;
mutex_lock(&priv->lock);
/* Clear mailbox registers. */
writel_relaxed(0, regs + REG_TO_DCPU_MBOX);
writel_relaxed(0, regs + REG_TO_HOST_MBOX);
@ -329,6 +355,8 @@ static void __enable_dcpu(void __iomem *regs)
val = readl_relaxed(regs + REG_DCPU_RESET);
val &= ~(1 << DCPU_RESET_SHIFT);
writel_relaxed(val, regs + REG_DCPU_RESET);
mutex_unlock(&priv->lock);
}
static unsigned int get_msg_chksum(const u32 msg[], unsigned int max)
@ -343,7 +371,7 @@ static unsigned int get_msg_chksum(const u32 msg[], unsigned int max)
return sum;
}
static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
static void __iomem *get_msg_ptr(struct brcmstb_dpfe_priv *priv, u32 response,
char *buf, ssize_t *size)
{
unsigned int msg_type;
@ -382,7 +410,7 @@ static void __iomem *get_msg_ptr(struct private_data *priv, u32 response,
return ptr;
}
static void __finalize_command(struct private_data *priv)
static void __finalize_command(struct brcmstb_dpfe_priv *priv)
{
unsigned int release_mbox;
@ -390,12 +418,12 @@ static void __finalize_command(struct private_data *priv)
* 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)
release_mbox = (priv->dpfe_api->version < 2)
? 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 brcmstb_dpfe_priv *priv, unsigned int cmd,
u32 result[])
{
const u32 *msg = priv->dpfe_api->command[cmd];
@ -421,9 +449,17 @@ static int __send_command(struct private_data *priv, unsigned int cmd,
return -ETIMEDOUT;
}
/* Compute checksum over the message */
chksum_idx = msg[MSG_ARG_COUNT] + MSG_ARG_COUNT + 1;
chksum = get_msg_chksum(msg, chksum_idx);
/* Write command and arguments to message area */
for (i = 0; i < MSG_FIELD_MAX; i++)
for (i = 0; i < MSG_FIELD_MAX; i++) {
if (i == chksum_idx)
writel_relaxed(chksum, regs + DCPU_MSG_RAM(i));
else
writel_relaxed(msg[i], regs + DCPU_MSG_RAM(i));
}
/* Tell DCPU there is a command waiting */
writel_relaxed(1, regs + REG_TO_DCPU_MBOX);
@ -517,7 +553,7 @@ static int __verify_firmware(struct init_data *init,
/* Verify checksum by reading back the firmware from co-processor RAM. */
static int __verify_fw_checksum(struct init_data *init,
struct private_data *priv,
struct brcmstb_dpfe_priv *priv,
const struct dpfe_firmware_header *header,
u32 checksum)
{
@ -571,26 +607,23 @@ static int __write_firmware(u32 __iomem *mem, const u32 *fw,
return 0;
}
static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
struct init_data *init)
static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv)
{
const struct dpfe_firmware_header *header;
unsigned int dmem_size, imem_size;
struct device *dev = &pdev->dev;
struct device *dev = priv->dev;
bool is_big_endian = false;
struct private_data *priv;
const struct firmware *fw;
const u32 *dmem, *imem;
struct init_data init;
const void *fw_blob;
int ret;
priv = platform_get_drvdata(pdev);
/*
* Skip downloading the firmware if the DCPU is already running and
* responding to commands.
*/
if (is_dcpu_enabled(priv->regs)) {
if (is_dcpu_enabled(priv)) {
u32 response[MSG_FIELD_MAX];
ret = __send_command(priv, DPFE_CMD_GET_INFO, response);
@ -606,20 +639,23 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
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. */
ret = firmware_request_nowarn(&fw, priv->dpfe_api->fw_name, dev);
/*
* Defer the firmware download if the firmware file couldn't be found.
* The root file system may not be available yet.
*/
if (ret)
return ret;
return (ret == -ENOENT) ? -EPROBE_DEFER : ret;
ret = __verify_firmware(init, fw);
ret = __verify_firmware(&init, fw);
if (ret)
return -EFAULT;
__disable_dcpu(priv->regs);
__disable_dcpu(priv);
is_big_endian = init->is_big_endian;
dmem_size = init->dmem_len;
imem_size = init->imem_len;
is_big_endian = init.is_big_endian;
dmem_size = init.dmem_len;
imem_size = init.imem_len;
/* At the beginning of the firmware blob is a header. */
header = (struct dpfe_firmware_header *)fw->data;
@ -637,17 +673,17 @@ static int brcmstb_dpfe_download_firmware(struct platform_device *pdev,
if (ret)
return ret;
ret = __verify_fw_checksum(init, priv, header, init->chksum);
ret = __verify_fw_checksum(&init, priv, header, init.chksum);
if (ret)
return ret;
__enable_dcpu(priv->regs);
__enable_dcpu(priv);
return 0;
}
static ssize_t generic_show(unsigned int command, u32 response[],
struct private_data *priv, char *buf)
struct brcmstb_dpfe_priv *priv, char *buf)
{
int ret;
@ -665,7 +701,7 @@ static ssize_t show_info(struct device *dev, struct device_attribute *devattr,
char *buf)
{
u32 response[MSG_FIELD_MAX];
struct private_data *priv;
struct brcmstb_dpfe_priv *priv;
unsigned int info;
ssize_t ret;
@ -688,7 +724,7 @@ static ssize_t show_refresh(struct device *dev,
{
u32 response[MSG_FIELD_MAX];
void __iomem *info;
struct private_data *priv;
struct brcmstb_dpfe_priv *priv;
u8 refresh, sr_abort, ppre, thermal_offs, tuf;
u32 mr4;
ssize_t ret;
@ -721,7 +757,7 @@ static ssize_t store_refresh(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
u32 response[MSG_FIELD_MAX];
struct private_data *priv;
struct brcmstb_dpfe_priv *priv;
void __iomem *info;
unsigned long val;
int ret;
@ -747,7 +783,7 @@ static ssize_t show_vendor(struct device *dev, struct device_attribute *devattr,
char *buf)
{
u32 response[MSG_FIELD_MAX];
struct private_data *priv;
struct brcmstb_dpfe_priv *priv;
void __iomem *info;
ssize_t ret;
u32 mr5, mr6, mr7, mr8, err;
@ -778,7 +814,7 @@ static ssize_t show_dram(struct device *dev, struct device_attribute *devattr,
char *buf)
{
u32 response[MSG_FIELD_MAX];
struct private_data *priv;
struct brcmstb_dpfe_priv *priv;
ssize_t ret;
u32 mr4, mr5, mr6, mr7, mr8, err;
@ -800,16 +836,15 @@ static ssize_t show_dram(struct device *dev, struct device_attribute *devattr,
static int brcmstb_dpfe_resume(struct platform_device *pdev)
{
struct init_data init;
struct brcmstb_dpfe_priv *priv = platform_get_drvdata(pdev);
return brcmstb_dpfe_download_firmware(pdev, &init);
return brcmstb_dpfe_download_firmware(priv);
}
static int brcmstb_dpfe_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct private_data *priv;
struct init_data init;
struct brcmstb_dpfe_priv *priv;
struct resource *res;
int ret;
@ -817,6 +852,8 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
priv->dev = dev;
mutex_init(&priv->lock);
platform_set_drvdata(pdev, priv);
@ -851,8 +888,9 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
return -ENOENT;
}
ret = brcmstb_dpfe_download_firmware(pdev, &init);
ret = brcmstb_dpfe_download_firmware(priv);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "Couldn't download firmware -- %d\n", ret);
return ret;
}
@ -867,7 +905,7 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev)
static int brcmstb_dpfe_remove(struct platform_device *pdev)
{
struct private_data *priv = dev_get_drvdata(&pdev->dev);
struct brcmstb_dpfe_priv *priv = dev_get_drvdata(&pdev->dev);
sysfs_remove_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs);
@ -876,10 +914,10 @@ static int brcmstb_dpfe_remove(struct platform_device *pdev)
static const struct of_device_id brcmstb_dpfe_of_match[] = {
/* 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 },
{ .compatible = "brcm,bcm7268-dpfe-cpu", .data = &dpfe_api_old_v2 },
{ .compatible = "brcm,bcm7271-dpfe-cpu", .data = &dpfe_api_old_v2 },
{ .compatible = "brcm,bcm7278-dpfe-cpu", .data = &dpfe_api_old_v2 },
{ .compatible = "brcm,bcm7211-dpfe-cpu", .data = &dpfe_api_new_v2 },
/* API v3 is the default going forward */
{ .compatible = "brcm,dpfe-cpu", .data = &dpfe_api_v3 },
{}