Commit ead67421 authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'qcom-soc-for-4.4' of git://codeaurora.org/quic/kernel/agross-msm into next/drivers

Pull "Qualcomm ARM Based SoC Updates for 4.4" from Andy Gross:

* Implement id_table driver matching in SMD
* Avoid NULL pointer exception on remove of SMEM
* Reorder SMEM/SMD configs
* Make qcom_smem_get() return a pointer
* Handle big endian CPUs correctly in SMEM
* Represent SMD channel layout in structures
* Use __iowrite32_copy() in SMD
* Remove use of VLAIs in SMD
* Handle big endian CPUs correctly in SMD/RPM
* Handle big endian CPUs corretly in SMD
* Reject sending SMD packets that are too large
* Fix endianness issue in SCM __qcom_scm_is_call_available
* Add missing prototype for qcom_scm_is_available()
* Correct SMEM items for upper channels
* Use architecture level to build SCM correctly
* Delete unneeded of_node_put in SMD
* Correct active/slep state flagging in SMD/RPM
* Move RPM message ram out of SMEM DT node

* tag 'qcom-soc-for-4.4' of git://codeaurora.org/quic/kernel/agross-msm:
  soc: qcom: smem: Move RPM message ram out of smem DT node
  soc: qcom: smd-rpm: Correct the active vs sleep state flagging
  soc: qcom: smd: delete unneeded of_node_put
  firmware: qcom-scm: build for correct architecture level
  soc: qcom: smd: Correct SMEM items for upper channels
  qcom-scm: add missing prototype for qcom_scm_is_available()
  qcom-scm: fix endianess issue in __qcom_scm_is_call_available
  soc: qcom: smd: Reject send of too big packets
  soc: qcom: smd: Handle big endian CPUs
  soc: qcom: smd_rpm: Handle big endian CPUs
  soc: qcom: smd: Remove use of VLAIS
  soc: qcom: smd: Use __iowrite32_copy() instead of open-coding it
  soc: qcom: smd: Represent channel layout in structures
  soc: qcom: smem: Handle big endian CPUs
  soc: qcom: Make qcom_smem_get() return a pointer
  soc: qcom: Reorder SMEM/SMD configs
  soc: qcom: smem: Avoid NULL pointer exception on remove
  soc: qcom: smd: Implement id_table driver matching
parents 41e602e8 d0bfd7c9
...@@ -100,6 +100,15 @@ timer { ...@@ -100,6 +100,15 @@ timer {
clock-frequency = <19200000>; clock-frequency = <19200000>;
}; };
smem {
compatible = "qcom,smem";
memory-region = <&smem_region>;
qcom,rpm-msg-ram = <&rpm_msg_ram>;
hwlocks = <&tcsr_mutex 3>;
};
soc: soc { soc: soc {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
...@@ -250,13 +259,9 @@ tcsr_mutex: tcsr-mutex { ...@@ -250,13 +259,9 @@ tcsr_mutex: tcsr-mutex {
#hwlock-cells = <1>; #hwlock-cells = <1>;
}; };
smem@fa00000 { rpm_msg_ram: memory@fc428000 {
compatible = "qcom,smem"; compatible = "qcom,rpm-msg-ram";
memory-region = <&smem_region>;
reg = <0xfc428000 0x4000>; reg = <0xfc428000 0x4000>;
hwlocks = <&tcsr_mutex 3>;
}; };
blsp1_uart2: serial@f991e000 { blsp1_uart2: serial@f991e000 {
......
...@@ -16,7 +16,7 @@ obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o ...@@ -16,7 +16,7 @@ obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o
obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
obj-y += broadcom/ obj-y += broadcom/
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
......
...@@ -480,15 +480,15 @@ void __qcom_scm_cpu_power_down(u32 flags) ...@@ -480,15 +480,15 @@ void __qcom_scm_cpu_power_down(u32 flags)
int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id) int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id)
{ {
int ret; int ret;
u32 svc_cmd = (svc_id << 10) | cmd_id; __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
u32 ret_val = 0; __le32 ret_val = 0;
ret = qcom_scm_call(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD, &svc_cmd, ret = qcom_scm_call(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD, &svc_cmd,
sizeof(svc_cmd), &ret_val, sizeof(ret_val)); sizeof(svc_cmd), &ret_val, sizeof(ret_val));
if (ret) if (ret)
return ret; return ret;
return ret_val; return le32_to_cpu(ret_val);
} }
int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp) int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
......
...@@ -19,6 +19,14 @@ config QCOM_PM ...@@ -19,6 +19,14 @@ config QCOM_PM
modes. It interface with various system drivers to put the cores in modes. It interface with various system drivers to put the cores in
low power modes. low power modes.
config QCOM_SMEM
tristate "Qualcomm Shared Memory Manager (SMEM)"
depends on ARCH_QCOM
help
Say y here to enable support for the Qualcomm Shared Memory Manager.
The driver provides an interface to items in a heap shared among all
processors in a Qualcomm platform.
config QCOM_SMD config QCOM_SMD
tristate "Qualcomm Shared Memory Driver (SMD)" tristate "Qualcomm Shared Memory Driver (SMD)"
depends on QCOM_SMEM depends on QCOM_SMEM
...@@ -40,11 +48,3 @@ config QCOM_SMD_RPM ...@@ -40,11 +48,3 @@ config QCOM_SMD_RPM
Say M here if you want to include support for the Qualcomm RPM as a Say M here if you want to include support for the Qualcomm RPM as a
module. This will build a module called "qcom-smd-rpm". module. This will build a module called "qcom-smd-rpm".
config QCOM_SMEM
tristate "Qualcomm Shared Memory Manager (SMEM)"
depends on ARCH_QCOM
help
Say y here to enable support for the Qualcomm Shared Memory Manager.
The driver provides an interface to items in a heap shared among all
processors in a Qualcomm platform.
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/soc/qcom/smd.h> #include <linux/soc/qcom/smd.h>
#include <linux/soc/qcom/smd-rpm.h> #include <linux/soc/qcom/smd-rpm.h>
...@@ -44,8 +45,8 @@ struct qcom_smd_rpm { ...@@ -44,8 +45,8 @@ struct qcom_smd_rpm {
* @length: length of the payload * @length: length of the payload
*/ */
struct qcom_rpm_header { struct qcom_rpm_header {
u32 service_type; __le32 service_type;
u32 length; __le32 length;
}; };
/** /**
...@@ -57,11 +58,11 @@ struct qcom_rpm_header { ...@@ -57,11 +58,11 @@ struct qcom_rpm_header {
* @data_len: length of the payload following this header * @data_len: length of the payload following this header
*/ */
struct qcom_rpm_request { struct qcom_rpm_request {
u32 msg_id; __le32 msg_id;
u32 flags; __le32 flags;
u32 type; __le32 type;
u32 id; __le32 id;
u32 data_len; __le32 data_len;
}; };
/** /**
...@@ -74,10 +75,10 @@ struct qcom_rpm_request { ...@@ -74,10 +75,10 @@ struct qcom_rpm_request {
* Multiple of these messages can be stacked in an rpm message. * Multiple of these messages can be stacked in an rpm message.
*/ */
struct qcom_rpm_message { struct qcom_rpm_message {
u32 msg_type; __le32 msg_type;
u32 length; __le32 length;
union { union {
u32 msg_id; __le32 msg_id;
u8 message[0]; u8 message[0];
}; };
}; };
...@@ -104,30 +105,34 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm, ...@@ -104,30 +105,34 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm,
static unsigned msg_id = 1; static unsigned msg_id = 1;
int left; int left;
int ret; int ret;
struct { struct {
struct qcom_rpm_header hdr; struct qcom_rpm_header hdr;
struct qcom_rpm_request req; struct qcom_rpm_request req;
u8 payload[count]; u8 payload[];
} pkt; } *pkt;
size_t size = sizeof(*pkt) + count;
/* SMD packets to the RPM may not exceed 256 bytes */ /* SMD packets to the RPM may not exceed 256 bytes */
if (WARN_ON(sizeof(pkt) >= 256)) if (WARN_ON(size >= 256))
return -EINVAL; return -EINVAL;
pkt = kmalloc(size, GFP_KERNEL);
if (!pkt)
return -ENOMEM;
mutex_lock(&rpm->lock); mutex_lock(&rpm->lock);
pkt.hdr.service_type = RPM_SERVICE_TYPE_REQUEST; pkt->hdr.service_type = cpu_to_le32(RPM_SERVICE_TYPE_REQUEST);
pkt.hdr.length = sizeof(struct qcom_rpm_request) + count; pkt->hdr.length = cpu_to_le32(sizeof(struct qcom_rpm_request) + count);
pkt.req.msg_id = msg_id++; pkt->req.msg_id = cpu_to_le32(msg_id++);
pkt.req.flags = BIT(state); pkt->req.flags = cpu_to_le32(state);
pkt.req.type = type; pkt->req.type = cpu_to_le32(type);
pkt.req.id = id; pkt->req.id = cpu_to_le32(id);
pkt.req.data_len = count; pkt->req.data_len = cpu_to_le32(count);
memcpy(pkt.payload, buf, count); memcpy(pkt->payload, buf, count);
ret = qcom_smd_send(rpm->rpm_channel, &pkt, sizeof(pkt)); ret = qcom_smd_send(rpm->rpm_channel, pkt, sizeof(*pkt));
if (ret) if (ret)
goto out; goto out;
...@@ -138,6 +143,7 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm, ...@@ -138,6 +143,7 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm,
ret = rpm->ack_status; ret = rpm->ack_status;
out: out:
kfree(pkt);
mutex_unlock(&rpm->lock); mutex_unlock(&rpm->lock);
return ret; return ret;
} }
...@@ -148,27 +154,29 @@ static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev, ...@@ -148,27 +154,29 @@ static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev,
size_t count) size_t count)
{ {
const struct qcom_rpm_header *hdr = data; const struct qcom_rpm_header *hdr = data;
size_t hdr_length = le32_to_cpu(hdr->length);
const struct qcom_rpm_message *msg; const struct qcom_rpm_message *msg;
struct qcom_smd_rpm *rpm = dev_get_drvdata(&qsdev->dev); struct qcom_smd_rpm *rpm = dev_get_drvdata(&qsdev->dev);
const u8 *buf = data + sizeof(struct qcom_rpm_header); const u8 *buf = data + sizeof(struct qcom_rpm_header);
const u8 *end = buf + hdr->length; const u8 *end = buf + hdr_length;
char msgbuf[32]; char msgbuf[32];
int status = 0; int status = 0;
u32 len; u32 len, msg_length;
if (hdr->service_type != RPM_SERVICE_TYPE_REQUEST || if (le32_to_cpu(hdr->service_type) != RPM_SERVICE_TYPE_REQUEST ||
hdr->length < sizeof(struct qcom_rpm_message)) { hdr_length < sizeof(struct qcom_rpm_message)) {
dev_err(&qsdev->dev, "invalid request\n"); dev_err(&qsdev->dev, "invalid request\n");
return 0; return 0;
} }
while (buf < end) { while (buf < end) {
msg = (struct qcom_rpm_message *)buf; msg = (struct qcom_rpm_message *)buf;
switch (msg->msg_type) { msg_length = le32_to_cpu(msg->length);
switch (le32_to_cpu(msg->msg_type)) {
case RPM_MSG_TYPE_MSG_ID: case RPM_MSG_TYPE_MSG_ID:
break; break;
case RPM_MSG_TYPE_ERR: case RPM_MSG_TYPE_ERR:
len = min_t(u32, ALIGN(msg->length, 4), sizeof(msgbuf)); len = min_t(u32, ALIGN(msg_length, 4), sizeof(msgbuf));
memcpy_fromio(msgbuf, msg->message, len); memcpy_fromio(msgbuf, msg->message, len);
msgbuf[len - 1] = 0; msgbuf[len - 1] = 0;
...@@ -179,7 +187,7 @@ static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev, ...@@ -179,7 +187,7 @@ static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev,
break; break;
} }
buf = PTR_ALIGN(buf + 2 * sizeof(u32) + msg->length, 4); buf = PTR_ALIGN(buf + 2 * sizeof(u32) + msg_length, 4);
} }
rpm->ack_status = status; rpm->ack_status = status;
......
This diff is collapsed.
This diff is collapsed.
...@@ -23,6 +23,8 @@ struct qcom_scm_hdcp_req { ...@@ -23,6 +23,8 @@ struct qcom_scm_hdcp_req {
u32 val; u32 val;
}; };
extern bool qcom_scm_is_available(void);
extern bool qcom_scm_hdcp_available(void); extern bool qcom_scm_hdcp_available(void);
extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp); u32 *resp);
......
...@@ -8,6 +8,14 @@ struct qcom_smd; ...@@ -8,6 +8,14 @@ struct qcom_smd;
struct qcom_smd_channel; struct qcom_smd_channel;
struct qcom_smd_lookup; struct qcom_smd_lookup;
/**
* struct qcom_smd_id - struct used for matching a smd device
* @name: name of the channel
*/
struct qcom_smd_id {
char name[20];
};
/** /**
* struct qcom_smd_device - smd device struct * struct qcom_smd_device - smd device struct
* @dev: the device struct * @dev: the device struct
...@@ -21,6 +29,7 @@ struct qcom_smd_device { ...@@ -21,6 +29,7 @@ struct qcom_smd_device {
/** /**
* struct qcom_smd_driver - smd driver struct * struct qcom_smd_driver - smd driver struct
* @driver: underlying device driver * @driver: underlying device driver
* @smd_match_table: static channel match table
* @probe: invoked when the smd channel is found * @probe: invoked when the smd channel is found
* @remove: invoked when the smd channel is closed * @remove: invoked when the smd channel is closed
* @callback: invoked when an inbound message is received on the channel, * @callback: invoked when an inbound message is received on the channel,
...@@ -29,6 +38,8 @@ struct qcom_smd_device { ...@@ -29,6 +38,8 @@ struct qcom_smd_device {
*/ */
struct qcom_smd_driver { struct qcom_smd_driver {
struct device_driver driver; struct device_driver driver;
const struct qcom_smd_id *smd_match_table;
int (*probe)(struct qcom_smd_device *dev); int (*probe)(struct qcom_smd_device *dev);
void (*remove)(struct qcom_smd_device *dev); void (*remove)(struct qcom_smd_device *dev);
int (*callback)(struct qcom_smd_device *, const void *, size_t); int (*callback)(struct qcom_smd_device *, const void *, size_t);
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#define QCOM_SMEM_HOST_ANY -1 #define QCOM_SMEM_HOST_ANY -1
int qcom_smem_alloc(unsigned host, unsigned item, size_t size); int qcom_smem_alloc(unsigned host, unsigned item, size_t size);
int qcom_smem_get(unsigned host, unsigned item, void **ptr, size_t *size); void *qcom_smem_get(unsigned host, unsigned item, size_t *size);
int qcom_smem_get_free_space(unsigned host); int qcom_smem_get_free_space(unsigned host);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment