firmware: xilinx: Add clock APIs
authorRajan Vaja <rajanv@xilinx.com>
Wed, 12 Sep 2018 19:38:38 +0000 (12:38 -0700)
committerMichal Simek <michal.simek@xilinx.com>
Wed, 26 Sep 2018 06:47:34 +0000 (08:47 +0200)
Add clock APIs to control clocks through firmware
interface.

Signed-off-by: Rajan Vaja <rajanv@xilinx.com>
Signed-off-by: Jolly Shah <jollys@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/firmware/xilinx/zynqmp.c
include/linux/firmware/xlnx-zynqmp.h

index 2a333c0..697f4fa 100644 (file)
@@ -250,13 +250,195 @@ static int get_set_conduit_method(struct device_node *np)
  */
 static int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
 {
-       return zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1,
-                                  qdata.arg2, qdata.arg3, out);
+       int ret;
+
+       ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1,
+                                 qdata.arg2, qdata.arg3, out);
+
+       /*
+        * For clock name query, all bytes in SMC response are clock name
+        * characters and return code is always success. For invalid clocks,
+        * clock name bytes would be zeros.
+        */
+       return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret;
+}
+
+/**
+ * zynqmp_pm_clock_enable() - Enable the clock for given id
+ * @clock_id:  ID of the clock to be enabled
+ *
+ * This function is used by master to enable the clock
+ * including peripherals and PLL clocks.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_enable(u32 clock_id)
+{
+       return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL);
+}
+
+/**
+ * zynqmp_pm_clock_disable() - Disable the clock for given id
+ * @clock_id:  ID of the clock to be disable
+ *
+ * This function is used by master to disable the clock
+ * including peripherals and PLL clocks.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_disable(u32 clock_id)
+{
+       return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL);
+}
+
+/**
+ * zynqmp_pm_clock_getstate() - Get the clock state for given id
+ * @clock_id:  ID of the clock to be queried
+ * @state:     1/0 (Enabled/Disabled)
+ *
+ * This function is used by master to get the state of clock
+ * including peripherals and PLL clocks.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state)
+{
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+       int ret;
+
+       ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0,
+                                 0, 0, ret_payload);
+       *state = ret_payload[1];
+
+       return ret;
+}
+
+/**
+ * zynqmp_pm_clock_setdivider() - Set the clock divider for given id
+ * @clock_id:  ID of the clock
+ * @divider:   divider value
+ *
+ * This function is used by master to set divider for any clock
+ * to achieve desired rate.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider)
+{
+       return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider,
+                                  0, 0, NULL);
+}
+
+/**
+ * zynqmp_pm_clock_getdivider() - Get the clock divider for given id
+ * @clock_id:  ID of the clock
+ * @divider:   divider value
+ *
+ * This function is used by master to get divider values
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
+{
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+       int ret;
+
+       ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0,
+                                 0, 0, ret_payload);
+       *divider = ret_payload[1];
+
+       return ret;
+}
+
+/**
+ * zynqmp_pm_clock_setrate() - Set the clock rate for given id
+ * @clock_id:  ID of the clock
+ * @rate:      rate value in hz
+ *
+ * This function is used by master to set rate for any clock.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate)
+{
+       return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id,
+                                  lower_32_bits(rate),
+                                  upper_32_bits(rate),
+                                  0, NULL);
+}
+
+/**
+ * zynqmp_pm_clock_getrate() - Get the clock rate for given id
+ * @clock_id:  ID of the clock
+ * @rate:      rate value in hz
+ *
+ * This function is used by master to get rate
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate)
+{
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+       int ret;
+
+       ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0,
+                                 0, 0, ret_payload);
+       *rate = ((u64)ret_payload[2] << 32) | ret_payload[1];
+
+       return ret;
+}
+
+/**
+ * zynqmp_pm_clock_setparent() - Set the clock parent for given id
+ * @clock_id:  ID of the clock
+ * @parent_id: parent id
+ *
+ * This function is used by master to set parent for any clock.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)
+{
+       return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id,
+                                  parent_id, 0, 0, NULL);
+}
+
+/**
+ * zynqmp_pm_clock_getparent() - Get the clock parent for given id
+ * @clock_id:  ID of the clock
+ * @parent_id: parent id
+ *
+ * This function is used by master to get parent index
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id)
+{
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+       int ret;
+
+       ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0,
+                                 0, 0, ret_payload);
+       *parent_id = ret_payload[1];
+
+       return ret;
 }
 
 static const struct zynqmp_eemi_ops eemi_ops = {
        .get_api_version = zynqmp_pm_get_api_version,
        .query_data = zynqmp_pm_query_data,
+       .clock_enable = zynqmp_pm_clock_enable,
+       .clock_disable = zynqmp_pm_clock_disable,
+       .clock_getstate = zynqmp_pm_clock_getstate,
+       .clock_setdivider = zynqmp_pm_clock_setdivider,
+       .clock_getdivider = zynqmp_pm_clock_getdivider,
+       .clock_setrate = zynqmp_pm_clock_setrate,
+       .clock_getrate = zynqmp_pm_clock_getrate,
+       .clock_setparent = zynqmp_pm_clock_setparent,
+       .clock_getparent = zynqmp_pm_clock_getparent,
 };
 
 /**
index 287f42c..015e130 100644 (file)
 enum pm_api_id {
        PM_GET_API_VERSION = 1,
        PM_QUERY_DATA = 35,
+       PM_CLOCK_ENABLE,
+       PM_CLOCK_DISABLE,
+       PM_CLOCK_GETSTATE,
+       PM_CLOCK_SETDIVIDER,
+       PM_CLOCK_GETDIVIDER,
+       PM_CLOCK_SETRATE,
+       PM_CLOCK_GETRATE,
+       PM_CLOCK_SETPARENT,
+       PM_CLOCK_GETPARENT,
 };
 
 /* PMU-FW return status codes */
@@ -48,8 +57,20 @@ enum pm_ret_status {
        XST_PM_ABORT_SUSPEND,
 };
 
+enum pm_ioctl_id {
+       IOCTL_SET_PLL_FRAC_MODE = 8,
+       IOCTL_GET_PLL_FRAC_MODE,
+       IOCTL_SET_PLL_FRAC_DATA,
+       IOCTL_GET_PLL_FRAC_DATA,
+};
+
 enum pm_query_id {
        PM_QID_INVALID,
+       PM_QID_CLOCK_GET_NAME,
+       PM_QID_CLOCK_GET_TOPOLOGY,
+       PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS,
+       PM_QID_CLOCK_GET_PARENTS,
+       PM_QID_CLOCK_GET_ATTRIBUTES,
 };
 
 /**
@@ -69,6 +90,15 @@ struct zynqmp_pm_query_data {
 struct zynqmp_eemi_ops {
        int (*get_api_version)(u32 *version);
        int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out);
+       int (*clock_enable)(u32 clock_id);
+       int (*clock_disable)(u32 clock_id);
+       int (*clock_getstate)(u32 clock_id, u32 *state);
+       int (*clock_setdivider)(u32 clock_id, u32 divider);
+       int (*clock_getdivider)(u32 clock_id, u32 *divider);
+       int (*clock_setrate)(u32 clock_id, u64 rate);
+       int (*clock_getrate)(u32 clock_id, u64 *rate);
+       int (*clock_setparent)(u32 clock_id, u32 parent_id);
+       int (*clock_getparent)(u32 clock_id, u32 *parent_id);
 };
 
 #if IS_REACHABLE(CONFIG_ARCH_ZYNQMP)