* GNU General Public License for more details.
*/
+#include <drm/drmP.h>
+#include <dt-bindings/display/rk_fb.h>
#include <linux/arm-smccc.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/rockchip/rockchip_sip.h>
#include <linux/slab.h>
#include <soc/rockchip/rockchip_sip.h>
#include <soc/rockchip/scpi.h>
+#include <uapi/drm/drm_mode.h>
#include "clk.h"
#define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw)
+static int rk_drm_get_lcdc_type(void)
+{
+ struct drm_device *drm;
+ u32 lcdc_type = 0;
+
+ drm = drm_device_get_by_name("rockchip");
+ if (drm) {
+ struct drm_connector *conn;
+
+ mutex_lock(&drm->mode_config.mutex);
+ drm_for_each_connector(conn, drm) {
+ if (conn->encoder) {
+ lcdc_type = conn->connector_type;
+ break;
+ }
+ }
+ mutex_unlock(&drm->mode_config.mutex);
+ }
+
+ switch (lcdc_type) {
+ case DRM_MODE_CONNECTOR_LVDS:
+ lcdc_type = SCREEN_LVDS;
+ break;
+ case DRM_MODE_CONNECTOR_DisplayPort:
+ lcdc_type = SCREEN_DP;
+ break;
+ case DRM_MODE_CONNECTOR_HDMIA:
+ case DRM_MODE_CONNECTOR_HDMIB:
+ lcdc_type = SCREEN_HDMI;
+ break;
+ case DRM_MODE_CONNECTOR_TV:
+ lcdc_type = SCREEN_TVOUT;
+ break;
+ case DRM_MODE_CONNECTOR_eDP:
+ lcdc_type = SCREEN_EDP;
+ break;
+ case DRM_MODE_CONNECTOR_DSI:
+ lcdc_type = SCREEN_MIPI;
+ break;
+ default:
+ lcdc_type = SCREEN_NULL;
+ break;
+ }
+
+ return lcdc_type;
+}
+
static int rockchip_ddrclk_sip_set_rate(struct clk_hw *hw, unsigned long drate,
unsigned long prate)
{
.get_parent = rockchip_ddrclk_get_parent,
};
+struct set_rate_params {
+ u32 hz;
+ /*
+ * 1: need to wait flag1
+ * 0: never wait flag1
+ */
+ u32 wait_flag1;
+ /*
+ * 1: need to wait flag1
+ * 0: never wait flag1
+ */
+ u32 wait_flag0;
+ /* these parameters, not use in RK322xh */
+ u32 lcdc_type;
+ u32 vop;
+ /* if need, add parameter after */
+};
+
+struct round_rate_params {
+ u32 hz;
+ /* if need, add parameter after */
+};
+
+struct rockchip_ddrclk_data {
+ u32 inited_flag;
+ void __iomem *share_memory;
+};
+
+static struct rockchip_ddrclk_data ddr_data;
+
+static void rockchip_ddrclk_data_init(void)
+{
+ struct arm_smccc_res res;
+
+ res = sip_smc_request_share_mem(1, SHARE_PAGE_TYPE_DDR);
+
+ if (!res.a0) {
+ ddr_data.share_memory = (void __iomem *)res.a1;
+ ddr_data.inited_flag = 1;
+ }
+}
+
+static int rockchip_ddrclk_sip_set_rate_v2(struct clk_hw *hw,
+ unsigned long drate,
+ unsigned long prate)
+{
+ struct set_rate_params *p;
+ struct arm_smccc_res res;
+
+ if (!ddr_data.inited_flag)
+ rockchip_ddrclk_data_init();
+
+ p = (struct set_rate_params *)ddr_data.share_memory;
+
+ p->hz = drate;
+ p->lcdc_type = rk_drm_get_lcdc_type();
+
+ res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
+ ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE);
+
+ return res.a0;
+}
+
+static unsigned long rockchip_ddrclk_sip_recalc_rate_v2
+ (struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct arm_smccc_res res;
+
+ res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
+ ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE);
+ if (!res.a0)
+ return res.a1;
+ else
+ return 0;
+}
+
+static long rockchip_ddrclk_sip_round_rate_v2(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *prate)
+{
+ struct round_rate_params *p;
+ struct arm_smccc_res res;
+
+ if (!ddr_data.inited_flag)
+ rockchip_ddrclk_data_init();
+
+ p = (struct round_rate_params *)ddr_data.share_memory;
+
+ p->hz = rate;
+
+ res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0,
+ ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE);
+ if (!res.a0)
+ return res.a1;
+ else
+ return 0;
+}
+
+static const struct clk_ops rockchip_ddrclk_sip_ops_v2 = {
+ .recalc_rate = rockchip_ddrclk_sip_recalc_rate_v2,
+ .set_rate = rockchip_ddrclk_sip_set_rate_v2,
+ .round_rate = rockchip_ddrclk_sip_round_rate_v2,
+ .get_parent = rockchip_ddrclk_get_parent,
+};
+
struct clk *rockchip_clk_register_ddrclk(const char *name, int flags,
const char *const *parent_names,
u8 num_parents, int mux_offset,
case ROCKCHIP_DDRCLK_SCPI:
init.ops = &rockchip_ddrclk_scpi_ops;
break;
+ case ROCKCHIP_DDRCLK_SIP_V2:
+ init.ops = &rockchip_ddrclk_sip_ops_v2;
+ break;
default:
pr_err("%s: unsupported ddrclk type %d\n", __func__, ddr_flag);
kfree(ddrclk);