diff options
author | YouMin Chen <cym@rock-chips.com> | 2018-08-21 15:28:44 +0800 |
---|---|---|
committer | Tao Huang <huangtao@rock-chips.com> | 2018-11-16 15:09:32 +0800 |
commit | 90cf7903d42bc0b1bb5d1868c42abe6cc51ad939 (patch) | |
tree | 0c246527dbc1d0c541b53a361e6e5d03012ee74a | |
parent | c475623bba9eabd3cd04d48d397195276aeff49f (diff) |
PM / devfreq: rockchip_dmc: add support for rk1808
Change-Id: If6a5230f84f8ea293f3d6c84f7586dbff3a02230
Signed-off-by: YouMin Chen <cym@rock-chips.com>
-rw-r--r-- | drivers/devfreq/rockchip_dmc.c | 463 | ||||
-rw-r--r-- | include/soc/rockchip/rockchip_sip.h | 1 |
2 files changed, 464 insertions, 0 deletions
diff --git a/drivers/devfreq/rockchip_dmc.c b/drivers/devfreq/rockchip_dmc.c index ba095fdfea96..17582fb6a795 100644 --- a/drivers/devfreq/rockchip_dmc.c +++ b/drivers/devfreq/rockchip_dmc.c @@ -29,6 +29,7 @@ #include <linux/input.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h> @@ -36,6 +37,7 @@ #include <linux/pm_opp.h> #include <linux/pm_qos.h> #include <linux/reboot.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/rockchip/rockchip_sip.h> #include <linux/rwsem.h> @@ -262,6 +264,310 @@ struct px30_ddr_dts_config_timing { unsigned int available; }; +static const char * const rk1808_dts_ca_timing[] = { + "a0_ddr3a9_de-skew", + "a1_ddr3a14_de-skew", + "a2_ddr3a13_de-skew", + "a3_ddr3a11_de-skew", + "a4_ddr3a2_de-skew", + "a5_ddr3a4_de-skew", + "a6_ddr3a3_de-skew", + "a7_ddr3a6_de-skew", + "a8_ddr3a5_de-skew", + "a9_ddr3a1_de-skew", + "a10_ddr3a0_de-skew", + "a11_ddr3a7_de-skew", + "a12_ddr3casb_de-skew", + "a13_ddr3a8_de-skew", + "a14_ddr3odt0_de-skew", + "a15_ddr3ba1_de-skew", + "a16_ddr3rasb_de-skew", + "a17_ddr3null_de-skew", + "ba0_ddr3ba2_de-skew", + "ba1_ddr3a12_de-skew", + "bg0_ddr3ba0_de-skew", + "bg1_ddr3web_de-skew", + "cke_ddr3cke_de-skew", + "ck_ddr3ck_de-skew", + "ckb_ddr3ckb_de-skew", + "csb0_ddr3a10_de-skew", + "odt0_ddr3a15_de-skew", + "resetn_ddr3resetn_de-skew", + "actn_ddr3csb0_de-skew", + "csb1_ddr3csb1_de-skew", + "odt1_ddr3odt1_de-skew", +}; + +static const char * const rk1808_dts_cs0_a_timing[] = { + "cs0_dm0_rx_de-skew", + "cs0_dm0_tx_de-skew", + "cs0_dq0_rx_de-skew", + "cs0_dq0_tx_de-skew", + "cs0_dq1_rx_de-skew", + "cs0_dq1_tx_de-skew", + "cs0_dq2_rx_de-skew", + "cs0_dq2_tx_de-skew", + "cs0_dq3_rx_de-skew", + "cs0_dq3_tx_de-skew", + "cs0_dq4_rx_de-skew", + "cs0_dq4_tx_de-skew", + "cs0_dq5_rx_de-skew", + "cs0_dq5_tx_de-skew", + "cs0_dq6_rx_de-skew", + "cs0_dq6_tx_de-skew", + "cs0_dq7_rx_de-skew", + "cs0_dq7_tx_de-skew", + "cs0_dqs0p_rx_de-skew", + "cs0_dqs0p_tx_de-skew", + "cs0_dqs0n_tx_de-skew", + "cs0_dm1_rx_de-skew", + "cs0_dm1_tx_de-skew", + "cs0_dq8_rx_de-skew", + "cs0_dq8_tx_de-skew", + "cs0_dq9_rx_de-skew", + "cs0_dq9_tx_de-skew", + "cs0_dq10_rx_de-skew", + "cs0_dq10_tx_de-skew", + "cs0_dq11_rx_de-skew", + "cs0_dq11_tx_de-skew", + "cs0_dq12_rx_de-skew", + "cs0_dq12_tx_de-skew", + "cs0_dq13_rx_de-skew", + "cs0_dq13_tx_de-skew", + "cs0_dq14_rx_de-skew", + "cs0_dq14_tx_de-skew", + "cs0_dq15_rx_de-skew", + "cs0_dq15_tx_de-skew", + "cs0_dqs1p_rx_de-skew", + "cs0_dqs1p_tx_de-skew", + "cs0_dqs1n_tx_de-skew", + "cs0_dqs0n_rx_de-skew", + "cs0_dqs1n_rx_de-skew", +}; + +static const char * const rk1808_dts_cs0_b_timing[] = { + "cs0_dm2_rx_de-skew", + "cs0_dm2_tx_de-skew", + "cs0_dq16_rx_de-skew", + "cs0_dq16_tx_de-skew", + "cs0_dq17_rx_de-skew", + "cs0_dq17_tx_de-skew", + "cs0_dq18_rx_de-skew", + "cs0_dq18_tx_de-skew", + "cs0_dq19_rx_de-skew", + "cs0_dq19_tx_de-skew", + "cs0_dq20_rx_de-skew", + "cs0_dq20_tx_de-skew", + "cs0_dq21_rx_de-skew", + "cs0_dq21_tx_de-skew", + "cs0_dq22_rx_de-skew", + "cs0_dq22_tx_de-skew", + "cs0_dq23_rx_de-skew", + "cs0_dq23_tx_de-skew", + "cs0_dqs2p_rx_de-skew", + "cs0_dqs2p_tx_de-skew", + "cs0_dqs2n_tx_de-skew", + "cs0_dm3_rx_de-skew", + "cs0_dm3_tx_de-skew", + "cs0_dq24_rx_de-skew", + "cs0_dq24_tx_de-skew", + "cs0_dq25_rx_de-skew", + "cs0_dq25_tx_de-skew", + "cs0_dq26_rx_de-skew", + "cs0_dq26_tx_de-skew", + "cs0_dq27_rx_de-skew", + "cs0_dq27_tx_de-skew", + "cs0_dq28_rx_de-skew", + "cs0_dq28_tx_de-skew", + "cs0_dq29_rx_de-skew", + "cs0_dq29_tx_de-skew", + "cs0_dq30_rx_de-skew", + "cs0_dq30_tx_de-skew", + "cs0_dq31_rx_de-skew", + "cs0_dq31_tx_de-skew", + "cs0_dqs3p_rx_de-skew", + "cs0_dqs3p_tx_de-skew", + "cs0_dqs3n_tx_de-skew", + "cs0_dqs2n_rx_de-skew", + "cs0_dqs3n_rx_de-skew", +}; + +static const char * const rk1808_dts_cs1_a_timing[] = { + "cs1_dm0_rx_de-skew", + "cs1_dm0_tx_de-skew", + "cs1_dq0_rx_de-skew", + "cs1_dq0_tx_de-skew", + "cs1_dq1_rx_de-skew", + "cs1_dq1_tx_de-skew", + "cs1_dq2_rx_de-skew", + "cs1_dq2_tx_de-skew", + "cs1_dq3_rx_de-skew", + "cs1_dq3_tx_de-skew", + "cs1_dq4_rx_de-skew", + "cs1_dq4_tx_de-skew", + "cs1_dq5_rx_de-skew", + "cs1_dq5_tx_de-skew", + "cs1_dq6_rx_de-skew", + "cs1_dq6_tx_de-skew", + "cs1_dq7_rx_de-skew", + "cs1_dq7_tx_de-skew", + "cs1_dqs0p_rx_de-skew", + "cs1_dqs0p_tx_de-skew", + "cs1_dqs0n_tx_de-skew", + "cs1_dm1_rx_de-skew", + "cs1_dm1_tx_de-skew", + "cs1_dq8_rx_de-skew", + "cs1_dq8_tx_de-skew", + "cs1_dq9_rx_de-skew", + "cs1_dq9_tx_de-skew", + "cs1_dq10_rx_de-skew", + "cs1_dq10_tx_de-skew", + "cs1_dq11_rx_de-skew", + "cs1_dq11_tx_de-skew", + "cs1_dq12_rx_de-skew", + "cs1_dq12_tx_de-skew", + "cs1_dq13_rx_de-skew", + "cs1_dq13_tx_de-skew", + "cs1_dq14_rx_de-skew", + "cs1_dq14_tx_de-skew", + "cs1_dq15_rx_de-skew", + "cs1_dq15_tx_de-skew", + "cs1_dqs1p_rx_de-skew", + "cs1_dqs1p_tx_de-skew", + "cs1_dqs1n_tx_de-skew", + "cs1_dqs0n_rx_de-skew", + "cs1_dqs1n_rx_de-skew", +}; + +static const char * const rk1808_dts_cs1_b_timing[] = { + "cs1_dm2_rx_de-skew", + "cs1_dm2_tx_de-skew", + "cs1_dq16_rx_de-skew", + "cs1_dq16_tx_de-skew", + "cs1_dq17_rx_de-skew", + "cs1_dq17_tx_de-skew", + "cs1_dq18_rx_de-skew", + "cs1_dq18_tx_de-skew", + "cs1_dq19_rx_de-skew", + "cs1_dq19_tx_de-skew", + "cs1_dq20_rx_de-skew", + "cs1_dq20_tx_de-skew", + "cs1_dq21_rx_de-skew", + "cs1_dq21_tx_de-skew", + "cs1_dq22_rx_de-skew", + "cs1_dq22_tx_de-skew", + "cs1_dq23_rx_de-skew", + "cs1_dq23_tx_de-skew", + "cs1_dqs2p_rx_de-skew", + "cs1_dqs2p_tx_de-skew", + "cs1_dqs2n_tx_de-skew", + "cs1_dm3_rx_de-skew", + "cs1_dm3_tx_de-skew", + "cs1_dq24_rx_de-skew", + "cs1_dq24_tx_de-skew", + "cs1_dq25_rx_de-skew", + "cs1_dq25_tx_de-skew", + "cs1_dq26_rx_de-skew", + "cs1_dq26_tx_de-skew", + "cs1_dq27_rx_de-skew", + "cs1_dq27_tx_de-skew", + "cs1_dq28_rx_de-skew", + "cs1_dq28_tx_de-skew", + "cs1_dq29_rx_de-skew", + "cs1_dq29_tx_de-skew", + "cs1_dq30_rx_de-skew", + "cs1_dq30_tx_de-skew", + "cs1_dq31_rx_de-skew", + "cs1_dq31_tx_de-skew", + "cs1_dqs3p_rx_de-skew", + "cs1_dqs3p_tx_de-skew", + "cs1_dqs3n_tx_de-skew", + "cs1_dqs2n_rx_de-skew", + "cs1_dqs3n_rx_de-skew", +}; + +struct rk1808_ddr_dts_config_timing { + unsigned int ddr2_speed_bin; + unsigned int ddr3_speed_bin; + unsigned int ddr4_speed_bin; + unsigned int pd_idle; + unsigned int sr_idle; + unsigned int sr_mc_gate_idle; + unsigned int srpd_lite_idle; + unsigned int standby_idle; + + unsigned int auto_pd_dis_freq; + unsigned int auto_sr_dis_freq; + /* for ddr2 only */ + unsigned int ddr2_dll_dis_freq; + /* for ddr3 only */ + unsigned int ddr3_dll_dis_freq; + /* for ddr4 only */ + unsigned int ddr4_dll_dis_freq; + unsigned int phy_dll_dis_freq; + + unsigned int ddr2_odt_dis_freq; + unsigned int phy_ddr2_odt_dis_freq; + unsigned int ddr2_drv; + unsigned int ddr2_odt; + unsigned int phy_ddr2_ca_drv; + unsigned int phy_ddr2_ck_drv; + unsigned int phy_ddr2_dq_drv; + unsigned int phy_ddr2_odt; + + unsigned int ddr3_odt_dis_freq; + unsigned int phy_ddr3_odt_dis_freq; + unsigned int ddr3_drv; + unsigned int ddr3_odt; + unsigned int phy_ddr3_ca_drv; + unsigned int phy_ddr3_ck_drv; + unsigned int phy_ddr3_dq_drv; + unsigned int phy_ddr3_odt; + + unsigned int phy_lpddr2_odt_dis_freq; + unsigned int lpddr2_drv; + unsigned int phy_lpddr2_ca_drv; + unsigned int phy_lpddr2_ck_drv; + unsigned int phy_lpddr2_dq_drv; + unsigned int phy_lpddr2_odt; + + unsigned int lpddr3_odt_dis_freq; + unsigned int phy_lpddr3_odt_dis_freq; + unsigned int lpddr3_drv; + unsigned int lpddr3_odt; + unsigned int phy_lpddr3_ca_drv; + unsigned int phy_lpddr3_ck_drv; + unsigned int phy_lpddr3_dq_drv; + unsigned int phy_lpddr3_odt; + + unsigned int lpddr4_odt_dis_freq; + unsigned int phy_lpddr4_odt_dis_freq; + unsigned int lpddr4_drv; + unsigned int lpddr4_dq_odt; + unsigned int lpddr4_ca_odt; + unsigned int phy_lpddr4_ca_drv; + unsigned int phy_lpddr4_ck_cs_drv; + unsigned int phy_lpddr4_dq_drv; + unsigned int phy_lpddr4_odt; + + unsigned int ddr4_odt_dis_freq; + unsigned int phy_ddr4_odt_dis_freq; + unsigned int ddr4_drv; + unsigned int ddr4_odt; + unsigned int phy_ddr4_ca_drv; + unsigned int phy_ddr4_ck_drv; + unsigned int phy_ddr4_dq_drv; + unsigned int phy_ddr4_odt; + + unsigned int ca_de_skew[31]; + unsigned int cs0_a_de_skew[44]; + unsigned int cs0_b_de_skew[44]; + unsigned int cs1_a_de_skew[44]; + unsigned int cs1_b_de_skew[44]; + + unsigned int available; +}; + static const char * const rk3128_dts_timing[] = { "ddr3_speed_bin", "pd_idle", @@ -1300,6 +1606,67 @@ end: of_node_put(np_tim); } +static void of_get_rk1808_timings(struct device *dev, + struct device_node *np, uint32_t *timing) +{ + struct device_node *np_tim; + u32 *p; + struct rk1808_ddr_dts_config_timing *dts_timing; + int ret = 0; + u32 i; + + dts_timing = + (struct rk1808_ddr_dts_config_timing *)(timing + + DTS_PAR_OFFSET / 4); + + np_tim = of_parse_phandle(np, "ddr_timing", 0); + if (!np_tim) { + ret = -EINVAL; + goto end; + } + + p = (u32 *)dts_timing; + for (i = 0; i < ARRAY_SIZE(px30_dts_timing); i++) { + ret |= of_property_read_u32(np_tim, px30_dts_timing[i], + p + i); + } + p = (u32 *)dts_timing->ca_de_skew; + for (i = 0; i < ARRAY_SIZE(rk1808_dts_ca_timing); i++) { + ret |= of_property_read_u32(np_tim, rk1808_dts_ca_timing[i], + p + i); + } + p = (u32 *)dts_timing->cs0_a_de_skew; + for (i = 0; i < ARRAY_SIZE(rk1808_dts_cs0_a_timing); i++) { + ret |= of_property_read_u32(np_tim, rk1808_dts_cs0_a_timing[i], + p + i); + } + p = (u32 *)dts_timing->cs0_b_de_skew; + for (i = 0; i < ARRAY_SIZE(rk1808_dts_cs0_b_timing); i++) { + ret |= of_property_read_u32(np_tim, rk1808_dts_cs0_b_timing[i], + p + i); + } + p = (u32 *)dts_timing->cs1_a_de_skew; + for (i = 0; i < ARRAY_SIZE(rk1808_dts_cs1_a_timing); i++) { + ret |= of_property_read_u32(np_tim, rk1808_dts_cs1_a_timing[i], + p + i); + } + p = (u32 *)dts_timing->cs1_b_de_skew; + for (i = 0; i < ARRAY_SIZE(rk1808_dts_cs1_b_timing); i++) { + ret |= of_property_read_u32(np_tim, rk1808_dts_cs1_b_timing[i], + p + i); + } + +end: + if (!ret) { + dts_timing->available = 1; + } else { + dts_timing->available = 0; + dev_err(dev, "of_get_ddr_timings: fail\n"); + } + + of_node_put(np_tim); +} + static void of_get_rk3128_timings(struct device *dev, struct device_node *np, uint32_t *timing) { @@ -1675,6 +2042,8 @@ struct dmcfreq_wait_ctrl_t { int wait_flag; int wait_en; int wait_time_out_ms; + int dcf_en; + struct regmap *regmap_dcf; }; static struct dmcfreq_wait_ctrl_t wait_ctrl; @@ -1688,6 +2057,21 @@ static irqreturn_t wait_complete_irq(int irqno, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t wait_dcf_complete_irq(int irqno, void *dev_id) +{ + struct arm_smccc_res res; + struct dmcfreq_wait_ctrl_t *ctrl = dev_id; + + res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, + ROCKCHIP_SIP_CONFIG_DRAM_POST_SET_RATE); + if (res.a0) + pr_err("%s: dram post set rate error:%lx\n", __func__, res.a0); + + ctrl->wait_flag = 0; + wake_up(&ctrl->wait_wq); + return IRQ_HANDLED; +} + int rockchip_dmcfreq_wait_complete(void) { if (!wait_ctrl.wait_en) { @@ -1702,6 +2086,11 @@ int rockchip_dmcfreq_wait_complete(void) */ pm_qos_update_request(&pm_qos, 0); + if (wait_ctrl.dcf_en == 1) { + /* start dcf */ + regmap_update_bits(wait_ctrl.regmap_dcf, 0x0, 0x1, 0x1); + } + wait_event_timeout(wait_ctrl.wait_wq, (wait_ctrl.wait_flag == 0), msecs_to_jiffies(wait_ctrl.wait_time_out_ms)); @@ -1781,6 +2170,77 @@ static __maybe_unused int px30_dmc_init(struct platform_device *pdev, return 0; } +static __maybe_unused int rk1808_dmc_init(struct platform_device *pdev, + struct rockchip_dmcfreq *dmcfreq) +{ + struct arm_smccc_res res; + u32 size; + int ret; + int complt_irq; + struct device_node *node; + + res = sip_smc_dram(0, 0, + ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION); + dev_notice(&pdev->dev, "current ATF version 0x%lx!\n", res.a1); + if (res.a0 || res.a1 < 0x101) { + dev_err(&pdev->dev, + "trusted firmware need to update or is invalid!\n"); + return -ENXIO; + } + + /* + * first 4KB is used for interface parameters + * after 4KB * N is dts parameters + */ + size = sizeof(struct rk1808_ddr_dts_config_timing); + res = sip_smc_request_share_mem(DIV_ROUND_UP(size, 4096) + 1, + SHARE_PAGE_TYPE_DDR); + if (res.a0 != 0) { + dev_err(&pdev->dev, "no ATF memory for init\n"); + return -ENOMEM; + } + ddr_psci_param = (struct share_params *)res.a1; + of_get_rk1808_timings(&pdev->dev, pdev->dev.of_node, + (uint32_t *)ddr_psci_param); + + /* enable start dcf in kernel after dcf ready */ + node = of_parse_phandle(pdev->dev.of_node, "dcf_reg", 0); + wait_ctrl.regmap_dcf = syscon_node_to_regmap(node); + if (IS_ERR(wait_ctrl.regmap_dcf)) + return PTR_ERR(wait_ctrl.regmap_dcf); + wait_ctrl.dcf_en = 1; + + init_waitqueue_head(&wait_ctrl.wait_wq); + wait_ctrl.wait_en = 1; + wait_ctrl.wait_time_out_ms = 17 * 5; + + complt_irq = platform_get_irq_byname(pdev, "complete_irq"); + if (complt_irq < 0) { + dev_err(&pdev->dev, "no IRQ for complete_irq: %d\n", + complt_irq); + return complt_irq; + } + + ret = devm_request_irq(&pdev->dev, complt_irq, wait_dcf_complete_irq, + 0, dev_name(&pdev->dev), &wait_ctrl); + if (ret < 0) { + dev_err(&pdev->dev, "cannot request complete_irq\n"); + return ret; + } + + res = sip_smc_dram(SHARE_PAGE_TYPE_DDR, 0, + ROCKCHIP_SIP_CONFIG_DRAM_INIT); + if (res.a0) { + dev_err(&pdev->dev, "rockchip_sip_config_dram_init error:%lx\n", + res.a0); + return -ENOMEM; + } + + dmcfreq->set_auto_self_refresh = rockchip_ddr_set_auto_self_refresh; + + return 0; +} + static __maybe_unused int rk3128_dmc_init(struct platform_device *pdev, struct rockchip_dmcfreq *dmcfreq) { @@ -2114,6 +2574,9 @@ static const struct of_device_id rockchip_dmcfreq_of_match[] = { #ifdef CONFIG_CPU_PX30 { .compatible = "rockchip,px30-dmc", .data = px30_dmc_init }, #endif +#ifdef CONFIG_CPU_RK1808 + { .compatible = "rockchip,rk1808-dmc", .data = rk1808_dmc_init }, +#endif #ifdef CONFIG_CPU_RK312X { .compatible = "rockchip,rk3128-dmc", .data = rk3128_dmc_init }, #endif diff --git a/include/soc/rockchip/rockchip_sip.h b/include/soc/rockchip/rockchip_sip.h index 7b72a57cc465..bca3ffb31655 100644 --- a/include/soc/rockchip/rockchip_sip.h +++ b/include/soc/rockchip/rockchip_sip.h @@ -24,5 +24,6 @@ #define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ 0x06 #define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM 0x07 #define ROCKCHIP_SIP_CONFIG_DRAM_GET_VERSION 0x08 +#define ROCKCHIP_SIP_CONFIG_DRAM_POST_SET_RATE 0x09 #endif |