summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2018-03-07 16:43:42 +0100
committerArnd Bergmann <arnd@arndb.de>2018-03-07 16:43:42 +0100
commit819d38e95f8ac3fb2e26e42e5c3f19d95a07c847 (patch)
treef7c627988511fd2bb321da46572b98eccaaa92de
parente107f4bb65e4ab55cf6a43af51254cd3e9c66066 (diff)
parent62c60efb63c868c1b1e54a1138c3295deae76eda (diff)
downloadlinux-819d38e95f8ac3fb2e26e42e5c3f19d95a07c847.tar.bz2
Merge tag 'scpi-updates-4.17' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into next/drivers
Pull "ARM SCPI updates/cleanups for v4.17" from Sudeep Holla: 1. Fixes to get rid of sparse warnings 2. Use of FIELD_GET and GENMASK for better subfields handling 3. Make mbox_free_channels device-managed helping in removing unnecessary code 4. Various other cleanups to simplify and improve code readability Note that similar set of changes were merged in v4.15, however got reverted through the commit 81faa5566864 ("firmware: arm_scpi: Revert updates made during v4.15 merge window") for reasons mentioned in that commit. This is the resend with the culprit patch removed. Kevin Hilman tested this series on Amlogic and reported it to be fine. * tag 'scpi-updates-4.17' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: firmware: arm_scpi: improve info message for pre-1.0 firmware firmware: arm_scpi: use FIELD_GET/_PREP to simplify macro definitions firmware: arm_scpi: remove struct sensor_capabilities firmware: arm_scpi: fix incorrect __iomem accesses using correct accessors firmware: arm_scpi: remove all single element structures firmware: arm_scpi: drop unnecessary type cast to scpi_shared_mem firmware: arm_scpi: improve struct sensor_value firmware: arm_scpi: improve handling of protocol and firmware version subfields firmware: arm_scpi: improve struct dvfs_info to make code better readable firmware: arm_scpi: make scpi_probe completely device-managed firmware: arm_scpi: make freeing mbox channels device-managed firmware: arm_scpi: remove two unneeded devm_kfree's in scpi_remove
-rw-r--r--drivers/firmware/arm_scpi.c211
1 files changed, 89 insertions, 122 deletions
diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
index 7da9f1b83ebe..6d7a6c0a5e07 100644
--- a/drivers/firmware/arm_scpi.c
+++ b/drivers/firmware/arm_scpi.c
@@ -28,6 +28,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/bitmap.h>
+#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
@@ -45,48 +46,32 @@
#include <linux/sort.h>
#include <linux/spinlock.h>
-#define CMD_ID_SHIFT 0
-#define CMD_ID_MASK 0x7f
-#define CMD_TOKEN_ID_SHIFT 8
-#define CMD_TOKEN_ID_MASK 0xff
-#define CMD_DATA_SIZE_SHIFT 16
-#define CMD_DATA_SIZE_MASK 0x1ff
-#define CMD_LEGACY_DATA_SIZE_SHIFT 20
-#define CMD_LEGACY_DATA_SIZE_MASK 0x1ff
-#define PACK_SCPI_CMD(cmd_id, tx_sz) \
- ((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \
- (((tx_sz) & CMD_DATA_SIZE_MASK) << CMD_DATA_SIZE_SHIFT))
-#define ADD_SCPI_TOKEN(cmd, token) \
- ((cmd) |= (((token) & CMD_TOKEN_ID_MASK) << CMD_TOKEN_ID_SHIFT))
-#define PACK_LEGACY_SCPI_CMD(cmd_id, tx_sz) \
- ((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \
- (((tx_sz) & CMD_LEGACY_DATA_SIZE_MASK) << CMD_LEGACY_DATA_SIZE_SHIFT))
-
-#define CMD_SIZE(cmd) (((cmd) >> CMD_DATA_SIZE_SHIFT) & CMD_DATA_SIZE_MASK)
-#define CMD_LEGACY_SIZE(cmd) (((cmd) >> CMD_LEGACY_DATA_SIZE_SHIFT) & \
- CMD_LEGACY_DATA_SIZE_MASK)
-#define CMD_UNIQ_MASK (CMD_TOKEN_ID_MASK << CMD_TOKEN_ID_SHIFT | CMD_ID_MASK)
+#define CMD_ID_MASK GENMASK(6, 0)
+#define CMD_TOKEN_ID_MASK GENMASK(15, 8)
+#define CMD_DATA_SIZE_MASK GENMASK(24, 16)
+#define CMD_LEGACY_DATA_SIZE_MASK GENMASK(28, 20)
+#define PACK_SCPI_CMD(cmd_id, tx_sz) \
+ (FIELD_PREP(CMD_ID_MASK, cmd_id) | \
+ FIELD_PREP(CMD_DATA_SIZE_MASK, tx_sz))
+#define PACK_LEGACY_SCPI_CMD(cmd_id, tx_sz) \
+ (FIELD_PREP(CMD_ID_MASK, cmd_id) | \
+ FIELD_PREP(CMD_LEGACY_DATA_SIZE_MASK, tx_sz))
+
+#define CMD_SIZE(cmd) FIELD_GET(CMD_DATA_SIZE_MASK, cmd)
+#define CMD_UNIQ_MASK (CMD_TOKEN_ID_MASK | CMD_ID_MASK)
#define CMD_XTRACT_UNIQ(cmd) ((cmd) & CMD_UNIQ_MASK)
#define SCPI_SLOT 0
#define MAX_DVFS_DOMAINS 8
#define MAX_DVFS_OPPS 16
-#define DVFS_LATENCY(hdr) (le32_to_cpu(hdr) >> 16)
-#define DVFS_OPP_COUNT(hdr) ((le32_to_cpu(hdr) >> 8) & 0xff)
-
-#define PROTOCOL_REV_MINOR_BITS 16
-#define PROTOCOL_REV_MINOR_MASK ((1U << PROTOCOL_REV_MINOR_BITS) - 1)
-#define PROTOCOL_REV_MAJOR(x) ((x) >> PROTOCOL_REV_MINOR_BITS)
-#define PROTOCOL_REV_MINOR(x) ((x) & PROTOCOL_REV_MINOR_MASK)
-
-#define FW_REV_MAJOR_BITS 24
-#define FW_REV_MINOR_BITS 16
-#define FW_REV_PATCH_MASK ((1U << FW_REV_MINOR_BITS) - 1)
-#define FW_REV_MINOR_MASK ((1U << FW_REV_MAJOR_BITS) - 1)
-#define FW_REV_MAJOR(x) ((x) >> FW_REV_MAJOR_BITS)
-#define FW_REV_MINOR(x) (((x) & FW_REV_MINOR_MASK) >> FW_REV_MINOR_BITS)
-#define FW_REV_PATCH(x) ((x) & FW_REV_PATCH_MASK)
+
+#define PROTO_REV_MAJOR_MASK GENMASK(31, 16)
+#define PROTO_REV_MINOR_MASK GENMASK(15, 0)
+
+#define FW_REV_MAJOR_MASK GENMASK(31, 24)
+#define FW_REV_MINOR_MASK GENMASK(23, 16)
+#define FW_REV_PATCH_MASK GENMASK(15, 0)
#define MAX_RX_TIMEOUT (msecs_to_jiffies(30))
@@ -311,10 +296,6 @@ struct clk_get_info {
u8 name[20];
} __packed;
-struct clk_get_value {
- __le32 rate;
-} __packed;
-
struct clk_set_value {
__le16 id;
__le16 reserved;
@@ -328,7 +309,9 @@ struct legacy_clk_set_value {
} __packed;
struct dvfs_info {
- __le32 header;
+ u8 domain;
+ u8 opp_count;
+ __le16 latency;
struct {
__le32 freq;
__le32 m_volt;
@@ -340,10 +323,6 @@ struct dvfs_set {
u8 index;
} __packed;
-struct sensor_capabilities {
- __le16 sensors;
-} __packed;
-
struct _scpi_sensor_info {
__le16 sensor_id;
u8 class;
@@ -351,11 +330,6 @@ struct _scpi_sensor_info {
char name[20];
};
-struct sensor_value {
- __le32 lo_val;
- __le32 hi_val;
-} __packed;
-
struct dev_pstate_set {
__le16 dev_id;
u8 pstate;
@@ -419,19 +393,20 @@ static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd)
unsigned int len;
if (scpi_info->is_legacy) {
- struct legacy_scpi_shared_mem *mem = ch->rx_payload;
+ struct legacy_scpi_shared_mem __iomem *mem =
+ ch->rx_payload;
/* RX Length is not replied by the legacy Firmware */
len = match->rx_len;
- match->status = le32_to_cpu(mem->status);
+ match->status = ioread32(&mem->status);
memcpy_fromio(match->rx_buf, mem->payload, len);
} else {
- struct scpi_shared_mem *mem = ch->rx_payload;
+ struct scpi_shared_mem __iomem *mem = ch->rx_payload;
- len = min(match->rx_len, CMD_SIZE(cmd));
+ len = min_t(unsigned int, match->rx_len, CMD_SIZE(cmd));
- match->status = le32_to_cpu(mem->status);
+ match->status = ioread32(&mem->status);
memcpy_fromio(match->rx_buf, mem->payload, len);
}
@@ -445,11 +420,11 @@ static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd)
static void scpi_handle_remote_msg(struct mbox_client *c, void *msg)
{
struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
- struct scpi_shared_mem *mem = ch->rx_payload;
+ struct scpi_shared_mem __iomem *mem = ch->rx_payload;
u32 cmd = 0;
if (!scpi_info->is_legacy)
- cmd = le32_to_cpu(mem->command);
+ cmd = ioread32(&mem->command);
scpi_process_cmd(ch, cmd);
}
@@ -459,7 +434,7 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg)
unsigned long flags;
struct scpi_xfer *t = msg;
struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
- struct scpi_shared_mem *mem = (struct scpi_shared_mem *)ch->tx_payload;
+ struct scpi_shared_mem __iomem *mem = ch->tx_payload;
if (t->tx_buf) {
if (scpi_info->is_legacy)
@@ -471,14 +446,14 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg)
if (t->rx_buf) {
if (!(++ch->token))
++ch->token;
- ADD_SCPI_TOKEN(t->cmd, ch->token);
+ t->cmd |= FIELD_PREP(CMD_TOKEN_ID_MASK, ch->token);
spin_lock_irqsave(&ch->rx_lock, flags);
list_add_tail(&t->node, &ch->rx_pending);
spin_unlock_irqrestore(&ch->rx_lock, flags);
}
if (!scpi_info->is_legacy)
- mem->command = cpu_to_le32(t->cmd);
+ iowrite32(t->cmd, &mem->command);
}
static struct scpi_xfer *get_scpi_xfer(struct scpi_chan *ch)
@@ -583,13 +558,13 @@ scpi_clk_get_range(u16 clk_id, unsigned long *min, unsigned long *max)
static unsigned long scpi_clk_get_val(u16 clk_id)
{
int ret;
- struct clk_get_value clk;
+ __le32 rate;
__le16 le_clk_id = cpu_to_le16(clk_id);
ret = scpi_send_message(CMD_GET_CLOCK_VALUE, &le_clk_id,
- sizeof(le_clk_id), &clk, sizeof(clk));
+ sizeof(le_clk_id), &rate, sizeof(rate));
- return ret ? ret : le32_to_cpu(clk.rate);
+ return ret ? ret : le32_to_cpu(rate);
}
static int scpi_clk_set_val(u16 clk_id, unsigned long rate)
@@ -665,8 +640,8 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain)
if (!info)
return ERR_PTR(-ENOMEM);
- info->count = DVFS_OPP_COUNT(buf.header);
- info->latency = DVFS_LATENCY(buf.header) * 1000; /* uS to nS */
+ info->count = buf.opp_count;
+ info->latency = le16_to_cpu(buf.latency) * 1000; /* uS to nS */
info->opps = kcalloc(info->count, sizeof(*opp), GFP_KERNEL);
if (!info->opps) {
@@ -713,9 +688,6 @@ static int scpi_dvfs_get_transition_latency(struct device *dev)
if (IS_ERR(info))
return PTR_ERR(info);
- if (!info->latency)
- return 0;
-
return info->latency;
}
@@ -746,13 +718,13 @@ static int scpi_dvfs_add_opps_to_device(struct device *dev)
static int scpi_sensor_get_capability(u16 *sensors)
{
- struct sensor_capabilities cap_buf;
+ __le16 cap;
int ret;
- ret = scpi_send_message(CMD_SENSOR_CAPABILITIES, NULL, 0, &cap_buf,
- sizeof(cap_buf));
+ ret = scpi_send_message(CMD_SENSOR_CAPABILITIES, NULL, 0, &cap,
+ sizeof(cap));
if (!ret)
- *sensors = le16_to_cpu(cap_buf.sensors);
+ *sensors = le16_to_cpu(cap);
return ret;
}
@@ -776,20 +748,19 @@ static int scpi_sensor_get_info(u16 sensor_id, struct scpi_sensor_info *info)
static int scpi_sensor_get_value(u16 sensor, u64 *val)
{
__le16 id = cpu_to_le16(sensor);
- struct sensor_value buf;
+ __le64 value;
int ret;
ret = scpi_send_message(CMD_SENSOR_VALUE, &id, sizeof(id),
- &buf, sizeof(buf));
+ &value, sizeof(value));
if (ret)
return ret;
if (scpi_info->is_legacy)
- /* only 32-bits supported, hi_val can be junk */
- *val = le32_to_cpu(buf.lo_val);
+ /* only 32-bits supported, upper 32 bits can be junk */
+ *val = le32_to_cpup((__le32 *)&value);
else
- *val = (u64)le32_to_cpu(buf.hi_val) << 32 |
- le32_to_cpu(buf.lo_val);
+ *val = le64_to_cpu(value);
return 0;
}
@@ -864,9 +835,9 @@ static ssize_t protocol_version_show(struct device *dev,
{
struct scpi_drvinfo *scpi_info = dev_get_drvdata(dev);
- return sprintf(buf, "%d.%d\n",
- PROTOCOL_REV_MAJOR(scpi_info->protocol_version),
- PROTOCOL_REV_MINOR(scpi_info->protocol_version));
+ return sprintf(buf, "%lu.%lu\n",
+ FIELD_GET(PROTO_REV_MAJOR_MASK, scpi_info->protocol_version),
+ FIELD_GET(PROTO_REV_MINOR_MASK, scpi_info->protocol_version));
}
static DEVICE_ATTR_RO(protocol_version);
@@ -875,10 +846,10 @@ static ssize_t firmware_version_show(struct device *dev,
{
struct scpi_drvinfo *scpi_info = dev_get_drvdata(dev);
- return sprintf(buf, "%d.%d.%d\n",
- FW_REV_MAJOR(scpi_info->firmware_version),
- FW_REV_MINOR(scpi_info->firmware_version),
- FW_REV_PATCH(scpi_info->firmware_version));
+ return sprintf(buf, "%lu.%lu.%lu\n",
+ FIELD_GET(FW_REV_MAJOR_MASK, scpi_info->firmware_version),
+ FIELD_GET(FW_REV_MINOR_MASK, scpi_info->firmware_version),
+ FIELD_GET(FW_REV_PATCH_MASK, scpi_info->firmware_version));
}
static DEVICE_ATTR_RO(firmware_version);
@@ -889,37 +860,26 @@ static struct attribute *versions_attrs[] = {
};
ATTRIBUTE_GROUPS(versions);
-static void
-scpi_free_channels(struct device *dev, struct scpi_chan *pchan, int count)
+static void scpi_free_channels(void *data)
{
+ struct scpi_drvinfo *info = data;
int i;
- for (i = 0; i < count && pchan->chan; i++, pchan++) {
- mbox_free_channel(pchan->chan);
- devm_kfree(dev, pchan->xfers);
- devm_iounmap(dev, pchan->rx_payload);
- }
+ for (i = 0; i < info->num_chans; i++)
+ mbox_free_channel(info->channels[i].chan);
}
static int scpi_remove(struct platform_device *pdev)
{
int i;
- struct device *dev = &pdev->dev;
struct scpi_drvinfo *info = platform_get_drvdata(pdev);
scpi_info = NULL; /* stop exporting SCPI ops through get_scpi_ops */
- of_platform_depopulate(dev);
- sysfs_remove_groups(&dev->kobj, versions_groups);
- scpi_free_channels(dev, info->channels, info->num_chans);
- platform_set_drvdata(pdev, NULL);
-
for (i = 0; i < MAX_DVFS_DOMAINS && info->dvfs[i]; i++) {
kfree(info->dvfs[i]->opps);
kfree(info->dvfs[i]);
}
- devm_kfree(dev, info->channels);
- devm_kfree(dev, info);
return 0;
}
@@ -952,7 +912,6 @@ static int scpi_probe(struct platform_device *pdev)
{
int count, idx, ret;
struct resource res;
- struct scpi_chan *scpi_chan;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
@@ -969,13 +928,19 @@ static int scpi_probe(struct platform_device *pdev)
return -ENODEV;
}
- scpi_chan = devm_kcalloc(dev, count, sizeof(*scpi_chan), GFP_KERNEL);
- if (!scpi_chan)
+ scpi_info->channels = devm_kcalloc(dev, count, sizeof(struct scpi_chan),
+ GFP_KERNEL);
+ if (!scpi_info->channels)
return -ENOMEM;
- for (idx = 0; idx < count; idx++) {
+ ret = devm_add_action(dev, scpi_free_channels, scpi_info);
+ if (ret)
+ return ret;
+
+ for (; scpi_info->num_chans < count; scpi_info->num_chans++) {
resource_size_t size;
- struct scpi_chan *pchan = scpi_chan + idx;
+ int idx = scpi_info->num_chans;
+ struct scpi_chan *pchan = scpi_info->channels + idx;
struct mbox_client *cl = &pchan->cl;
struct device_node *shmem = of_parse_phandle(np, "shmem", idx);
@@ -983,15 +948,14 @@ static int scpi_probe(struct platform_device *pdev)
of_node_put(shmem);
if (ret) {
dev_err(dev, "failed to get SCPI payload mem resource\n");
- goto err;
+ return ret;
}
size = resource_size(&res);
pchan->rx_payload = devm_ioremap(dev, res.start, size);
if (!pchan->rx_payload) {
dev_err(dev, "failed to ioremap SCPI payload\n");
- ret = -EADDRNOTAVAIL;
- goto err;
+ return -EADDRNOTAVAIL;
}
pchan->tx_payload = pchan->rx_payload + (size >> 1);
@@ -1017,14 +981,9 @@ static int scpi_probe(struct platform_device *pdev)
dev_err(dev, "failed to get channel%d err %d\n",
idx, ret);
}
-err:
- scpi_free_channels(dev, scpi_chan, idx);
- scpi_info = NULL;
return ret;
}
- scpi_info->channels = scpi_chan;
- scpi_info->num_chans = count;
scpi_info->commands = scpi_std_commands;
platform_set_drvdata(pdev, scpi_info);
@@ -1043,23 +1002,31 @@ err:
ret = scpi_init_versions(scpi_info);
if (ret) {
dev_err(dev, "incorrect or no SCP firmware found\n");
- scpi_remove(pdev);
return ret;
}
- _dev_info(dev, "SCP Protocol %d.%d Firmware %d.%d.%d version\n",
- PROTOCOL_REV_MAJOR(scpi_info->protocol_version),
- PROTOCOL_REV_MINOR(scpi_info->protocol_version),
- FW_REV_MAJOR(scpi_info->firmware_version),
- FW_REV_MINOR(scpi_info->firmware_version),
- FW_REV_PATCH(scpi_info->firmware_version));
+ if (scpi_info->is_legacy && !scpi_info->protocol_version &&
+ !scpi_info->firmware_version)
+ dev_info(dev, "SCP Protocol legacy pre-1.0 firmware\n");
+ else
+ dev_info(dev, "SCP Protocol %lu.%lu Firmware %lu.%lu.%lu version\n",
+ FIELD_GET(PROTO_REV_MAJOR_MASK,
+ scpi_info->protocol_version),
+ FIELD_GET(PROTO_REV_MINOR_MASK,
+ scpi_info->protocol_version),
+ FIELD_GET(FW_REV_MAJOR_MASK,
+ scpi_info->firmware_version),
+ FIELD_GET(FW_REV_MINOR_MASK,
+ scpi_info->firmware_version),
+ FIELD_GET(FW_REV_PATCH_MASK,
+ scpi_info->firmware_version));
scpi_info->scpi_ops = &scpi_ops;
- ret = sysfs_create_groups(&dev->kobj, versions_groups);
+ ret = devm_device_add_groups(dev, versions_groups);
if (ret)
dev_err(dev, "unable to create sysfs version group\n");
- return of_platform_populate(dev->of_node, NULL, NULL, dev);
+ return devm_of_platform_populate(dev);
}
static const struct of_device_id scpi_of_match[] = {