rk3368 ddr: add configure ddr timing function
[firefly-linux-kernel-4.4.55.git] / drivers / mailbox / scpi_protocol.c
index d906906fdbd71dc66f8705703281adf2a0e06f25..c58a608596f781c78dbaa80eef51f79380d85189 100644 (file)
 #define DVFS_LATENCY(hdr)      ((hdr) >> 16)
 #define DVFS_OPP_COUNT(hdr)    (((hdr) >> 8) & 0xff)
 
+static int max_chan_num = 0;
+static DECLARE_BITMAP(bm_mbox_chans, 4);
+static DEFINE_MUTEX(scpi_mtx);
+
 struct scpi_data_buf {
        int client_id;
        struct rockchip_mbox_msg *data;
@@ -55,6 +59,11 @@ struct scpi_data_buf {
        int timeout_ms;
 };
 
+struct scpi_mcu_ver {
+       u32  scpi_ver;
+       char mcu_ver[16];
+};
+
 static int high_priority_cmds[] = {
        SCPI_CMD_GET_CSS_PWR_STATE,
        SCPI_CMD_CFG_PWR_STATE_STAT,
@@ -89,7 +98,7 @@ static inline int scpi_to_linux_errno(int errno)
        return -EIO;
 }
 
-static bool high_priority_chan_supported(int cmd)
+static bool __maybe_unused high_priority_chan_supported(int cmd)
 {
        int idx;
 
@@ -99,6 +108,37 @@ static bool high_priority_chan_supported(int cmd)
        return false;
 }
 
+static int scpi_alloc_mbox_chan(void)
+{
+       int index;
+
+       mutex_lock(&scpi_mtx);
+
+       index = find_first_zero_bit(bm_mbox_chans, max_chan_num);
+       if (index >= max_chan_num) {
+               pr_err("alloc mailbox channel failed\n");
+               mutex_unlock(&scpi_mtx);
+               return -EBUSY;
+       }
+
+       set_bit(index, bm_mbox_chans);
+
+       mutex_unlock(&scpi_mtx);
+       return index;
+}
+
+static void scpi_free_mbox_chan(int chan)
+{
+       int index = chan;
+
+       mutex_lock(&scpi_mtx);
+
+       if (index < max_chan_num && index >= 0)
+               clear_bit(index, bm_mbox_chans);
+
+       mutex_unlock(&scpi_mtx);
+}
+
 static void scpi_rx_callback(struct mbox_client *cl, void *msg)
 {
        struct rockchip_mbox_msg *data = (struct rockchip_mbox_msg *)msg;
@@ -107,7 +147,7 @@ static void scpi_rx_callback(struct mbox_client *cl, void *msg)
        complete(&scpi_buf->complete);
 }
 
-static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, bool high_priority)
+static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, int index)
 {
        struct mbox_chan *chan;
        struct mbox_client cl;
@@ -127,9 +167,11 @@ static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, bool high_priority)
        cl.tx_block = false;
        cl.knows_txdone = false;
 
-       chan = mbox_request_channel(&cl, high_priority);
-       if (IS_ERR(chan))
+       chan = mbox_request_channel(&cl, index);
+       if (IS_ERR(chan)) {
+               scpi_free_mbox_chan(index);
                return PTR_ERR(chan);
+       }
 
        init_completion(&scpi_buf->complete);
        if (mbox_send_message(chan, (void *)data) < 0) {
@@ -146,6 +188,7 @@ static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, bool high_priority)
 
 free_channel:
        mbox_free_channel(chan);
+       scpi_free_mbox_chan(index);
 
        return scpi_to_linux_errno(status);
 }
@@ -164,21 +207,38 @@ do {                                              \
        scpi_buf.timeout_ms = SCPI_CMD_DEFAULT_TIMEOUT_MS; \
 } while (0)
 
+#define SCPI_SETUP_DBUF_BY_SIZE(scpi_buf, mbox_buf, _client_id,                \
+                               _cmd, _tx_buf, _tx_size, _rx_buf)       \
+do {                                                                   \
+       struct rockchip_mbox_msg *pdata = &mbox_buf;                    \
+       pdata->cmd = _cmd;                                              \
+       pdata->tx_buf = _tx_buf;                                        \
+       pdata->tx_size = _tx_size;                                      \
+       pdata->rx_buf = &_rx_buf;                                       \
+       pdata->rx_size = sizeof(_rx_buf);                               \
+       scpi_buf.client_id = _client_id;                                \
+       scpi_buf.data = pdata;                                          \
+       scpi_buf.timeout_ms = SCPI_CMD_DEFAULT_TIMEOUT_MS;              \
+} while (0)
+
 static int scpi_execute_cmd(struct scpi_data_buf *scpi_buf)
 {
        struct rockchip_mbox_msg *data;
-       bool high_priority;
+       int index;
 
        if (!scpi_buf || !scpi_buf->data)
                return -EINVAL;
 
+       index = scpi_alloc_mbox_chan();
+       if (index < 0)
+               return -EBUSY;
+
        data = scpi_buf->data;
-       high_priority = high_priority_chan_supported(data->cmd);
        data->cmd = PACK_SCPI_CMD(data->cmd, scpi_buf->client_id,
                                  data->tx_size);
        data->cl_data = scpi_buf;
 
-       return send_scpi_cmd(scpi_buf, high_priority);
+       return send_scpi_cmd(scpi_buf, index);
 }
 
 unsigned long scpi_clk_get_val(u16 clk_id)
@@ -383,23 +443,29 @@ int scpi_get_sensor_value(u16 sensor, u32 *val)
 }
 EXPORT_SYMBOL_GPL(scpi_get_sensor_value);
 
-static int scpi_get_version(u32 old, u32 *ver)
+static int scpi_get_version(u32 old, struct scpi_mcu_ver *ver)
 {
+       int ret;
        struct scpi_data_buf sdata;
        struct rockchip_mbox_msg mdata;
        struct __packed {
                u32 status;
-               u32 ver;
+               struct scpi_mcu_ver version;
        } buf;
-       int ret;
 
+       memset(&buf, 0, sizeof(buf));
        SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_SYS, SCPI_SYS_GET_VERSION,
                        old, buf);
 
        ret = scpi_execute_cmd(&sdata);
-       if (ret)
-               *ver = buf.ver;
+       if (ret) {
+               pr_err("get scpi version from MCU failed, ret=%d\n", ret);
+               goto OUT;
+       }
 
+       memcpy(ver, &(buf.version), sizeof(*ver));
+
+OUT:
        return ret;
 }
 
@@ -440,7 +506,7 @@ int scpi_sys_set_mcu_state_resume(void)
 }
 EXPORT_SYMBOL_GPL(scpi_sys_set_mcu_state_resume);
 
-int scpi_ddr_init(u32 dram_speed_bin, u32 freq, u32 lcdc_type)
+int scpi_ddr_init(u32 dram_speed_bin, u32 freq, u32 lcdc_type, u32 addr_mcu_el3)
 {
        struct scpi_data_buf sdata;
        struct rockchip_mbox_msg mdata;
@@ -448,6 +514,7 @@ int scpi_ddr_init(u32 dram_speed_bin, u32 freq, u32 lcdc_type)
                u32 dram_speed_bin;
                u32 freq;
                u32 lcdc_type;
+               u32 addr_mcu_el3;
        } tx_buf;
        struct __packed2 {
                u32 status;
@@ -456,32 +523,46 @@ int scpi_ddr_init(u32 dram_speed_bin, u32 freq, u32 lcdc_type)
        tx_buf.dram_speed_bin = (u32)dram_speed_bin;
        tx_buf.freq = (u32)freq;
        tx_buf.lcdc_type = (u32)lcdc_type;
-
+       tx_buf.addr_mcu_el3 = addr_mcu_el3;
        SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
                        SCPI_DDR_INIT, tx_buf, rx_buf);
        return scpi_execute_cmd(&sdata);
 }
 EXPORT_SYMBOL_GPL(scpi_ddr_init);
 
-int scpi_ddr_set_clk_rate(u32 rate)
+int scpi_ddr_set_clk_rate(u32 rate, u32 lcdc_type)
 {
        struct scpi_data_buf sdata;
        struct rockchip_mbox_msg mdata;
        struct __packed1 {
                u32 clk_rate;
+               u32 lcdc_type;
        } tx_buf;
        struct __packed2 {
                u32 status;
        } rx_buf;
 
        tx_buf.clk_rate = (u32)rate;
-
+       tx_buf.lcdc_type = (u32)lcdc_type;
        SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
                        SCPI_DDR_SET_FREQ, tx_buf, rx_buf);
        return scpi_execute_cmd(&sdata);
 }
 EXPORT_SYMBOL_GPL(scpi_ddr_set_clk_rate);
 
+int scpi_ddr_send_timing(u32 *p, u32 size)
+{
+       struct scpi_data_buf sdata;
+       struct rockchip_mbox_msg mdata;
+       struct __packed2 {
+               u32 status;
+       } rx_buf;
+       SCPI_SETUP_DBUF_BY_SIZE(sdata, mdata, SCPI_CL_DDR,
+                               SCPI_DDR_SEND_TIMING, p, size, rx_buf);
+       return scpi_execute_cmd(&sdata);
+}
+EXPORT_SYMBOL_GPL(scpi_ddr_send_timing);
+
 int scpi_ddr_round_rate(u32 m_hz)
 {
        struct scpi_data_buf sdata;
@@ -574,6 +655,54 @@ int scpi_ddr_get_clk_rate(void)
 }
 EXPORT_SYMBOL_GPL(scpi_ddr_get_clk_rate);
 
+int scpi_thermal_get_temperature(void)
+{
+       int ret;
+       struct scpi_data_buf sdata;
+       struct rockchip_mbox_msg mdata;
+       struct __packed1 {
+               u32 status;
+       } tx_buf;
+
+       struct __packed2 {
+               u32 status;
+               u32 tsadc_data;
+       } rx_buf;
+
+       tx_buf.status = 0;
+       SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_THERMAL,
+                       SCPI_THERMAL_GET_TSADC_DATA, tx_buf, rx_buf);
+
+       ret = scpi_execute_cmd(&sdata);
+       if (ret) {
+               pr_err("get temperature from MCU failed, ret=%d\n", ret);
+               return ret;
+       }
+
+       return rx_buf.tsadc_data;
+}
+EXPORT_SYMBOL_GPL(scpi_thermal_get_temperature);
+
+int scpi_thermal_set_clk_cycle(u32 cycle)
+{
+       struct scpi_data_buf sdata;
+       struct rockchip_mbox_msg mdata;
+       struct __packed1 {
+               u32 clk_cycle;
+       } tx_buf;
+
+       struct __packed2 {
+               u32 status;
+       } rx_buf;
+
+       tx_buf.clk_cycle = cycle;
+       SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_THERMAL,
+                       SCPI_THERMAL_SET_TSADC_CYCLE, tx_buf, rx_buf);
+
+       return scpi_execute_cmd(&sdata);
+}
+EXPORT_SYMBOL_GPL(scpi_thermal_set_clk_cycle);
+
 static struct of_device_id mobx_scpi_of_match[] = {
        { .compatible = "rockchip,mbox-scpi"},
        { },
@@ -584,25 +713,42 @@ static int mobx_scpi_probe(struct platform_device *pdev)
 {
        int ret = 0;
        int retry = 3;
-       u32 ver = 0;
-       int check_version = 0; /*0: not check version, 1: check version*/
+       int val = 0;
+       struct scpi_mcu_ver mcu_ver;
+       int check_version = 1; /*0: not check version, 1: check version*/
 
        the_scpi_device = &pdev->dev;
 
+       /* try to get mboxes chan nums from DT */
+       if (of_property_read_u32((&pdev->dev)->of_node, "chan-nums", &val)) {
+               dev_err(&pdev->dev, "parse mboxes chan-nums failed\n");
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       max_chan_num = val;
+
+       /* try to check up with SCPI version from MCU */
        while ((retry--) && (check_version != 0)) {
-               ret = scpi_get_version(SCPI_VERSION, &ver);
-               if ((ret == 0) && (ver == SCPI_VERSION))
+               memset(&mcu_ver, 0, sizeof(mcu_ver));
+
+               ret = scpi_get_version(SCPI_VERSION, &mcu_ver);
+               if ((ret == 0) && (mcu_ver.scpi_ver == SCPI_VERSION))
                        break;
        }
 
        if ((retry <= 0) && (check_version != 0)) {
-               dev_err(&pdev->dev, "Failed to get scpi version\n");
+               dev_err(&pdev->dev,
+                       "Scpi verison not match:kernel ver:0x%x, MCU ver:0x%x, ret=%d\n",
+                       SCPI_VERSION, mcu_ver.scpi_ver, ret);
                ret = -EIO;
                goto exit;
        }
 
-       dev_info(&pdev->dev,
-                "Scpi initialize, version: 0x%x\n", ver);
+       dev_info(&pdev->dev, "Scpi initialize, version: 0x%x, chan nums: %d\n",
+                mcu_ver.scpi_ver, val);
+       dev_info(&pdev->dev, "MCU version: %s\n", mcu_ver.mcu_ver);
+
        return 0;
 exit:
        the_scpi_device = NULL;