#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <dt-bindings/clock/ddr.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
#include <linux/of.h>
-#include <linux/of_address.h>
#include <linux/platform_device.h>
-#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
-
-#include <linux/kernel.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/clk.h>
-#include <linux/delay.h>
-
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-#include <linux/cpu.h>
-#include <dt-bindings/clock/ddr.h>
-#include <linux/rockchip/common.h>
-#include <linux/rockchip/cpu.h>
-#include <linux/rockchip/cru.h>
-#include <linux/rockchip/dvfs.h>
-#include <linux/rockchip/grf.h>
-#include <linux/rockchip/iomap.h>
-#include <linux/rockchip/pmu.h>
#include <linux/rk_fb.h>
+#include <linux/rockchip/common.h>
+#include <linux/rockchip/psci.h>
#include <linux/scpi_protocol.h>
+#include <asm/compiler.h>
#define GRF_DDRC0_CON0 0x600
#define GRF_SOC_STATUS5 0x494
#define DDR_PCTL_TOGCNT_1U 0xc0
+#define FIQ_CPU_TGT_BOOT 0x0 /* to booting cpu */
+#define FIQ_NUM_FOR_DCF (143) /*NA irq map to fiq for dcf*/
+
+
+#define DDR_VERSION "V1.03 20150910"
+
enum ddr_bandwidth_id {
ddrbw_wr_num = 0,
ddrbw_rd_num,
ddrbw_id_end
};
+struct ddr_timing {
+ u32 dram_spd_bin;
+ u32 sr_idle;
+ u32 pd_idle;
+ u32 dram_dll_dis_freq;
+ u32 phy_dll_dis_freq;
+ u32 dram_odt_dis_freq;
+ u32 phy_odt_dis_freq;
+ u32 ddr3_drv;
+ u32 ddr3_odt;
+ u32 lpddr3_drv;
+ u32 lpddr3_odt;
+ u32 lpddr2_drv;
+ u32 phy_clk_drv;
+ u32 phy_cmd_drv;
+ u32 phy_dqs_drv;
+ u32 phy_odt;
+};
+
struct rockchip_ddr {
struct regmap *ddrpctl_regs;
struct regmap *msch_regs;
struct regmap *grf_regs;
+ struct ddr_timing dram_timing;
};
static struct rockchip_ddr *ddr_data = NULL;
+static int of_do_get_timings(struct device_node *np, struct ddr_timing *tim)
+{
+ struct device_node *np_tim;
+ int ret;
+
+ ret = 0;
+
+ np_tim = of_parse_phandle(np, "rockchip,ddr_timing", 0);
+ if (!np_tim)
+ return 1;
+
+ ret |= of_property_read_u32(np_tim, "dram_spd_bin",
+ &tim->dram_spd_bin);
+ ret |= of_property_read_u32(np_tim, "sr_idle", &tim->sr_idle);
+ ret |= of_property_read_u32(np_tim, "pd_idle", &tim->pd_idle);
+ ret |= of_property_read_u32(np_tim, "dram_dll_disb_freq",
+ &tim->dram_dll_dis_freq);
+ ret |= of_property_read_u32(np_tim, "phy_dll_disb_freq",
+ &tim->phy_dll_dis_freq);
+ ret |= of_property_read_u32(np_tim, "dram_odt_disb_freq",
+ &tim->dram_odt_dis_freq);
+ ret |= of_property_read_u32(np_tim, "phy_odt_disb_freq",
+ &tim->phy_odt_dis_freq);
+ ret |= of_property_read_u32(np_tim, "ddr3_drv", &tim->ddr3_drv);
+ ret |= of_property_read_u32(np_tim, "ddr3_odt", &tim->ddr3_odt);
+ ret |= of_property_read_u32(np_tim, "lpddr3_drv", &tim->lpddr3_drv);
+ ret |= of_property_read_u32(np_tim, "lpddr3_odt", &tim->lpddr3_odt);
+ ret |= of_property_read_u32(np_tim, "lpddr2_drv", &tim->lpddr2_drv);
+ ret |= of_property_read_u32(np_tim, "phy_clk_drv", &tim->phy_clk_drv);
+ ret |= of_property_read_u32(np_tim, "phy_cmd_drv", &tim->phy_cmd_drv);
+ ret |= of_property_read_u32(np_tim, "phy_dqs_drv", &tim->phy_dqs_drv);
+ ret |= of_property_read_u32(np_tim, "phy_odt", &tim->phy_odt);
+
+ return ret;
+}
+
+static int _ddr_recalc_rate(void)
+{
+ int ddr_freq;
+
+ regmap_read(ddr_data->ddrpctl_regs, DDR_PCTL_TOGCNT_1U,
+ &ddr_freq);
+ ddr_freq = ddr_freq * 2 * 1000000;
+ return ddr_freq;
+}
+
static int _ddr_change_freq(u32 n_mhz)
{
u32 ret;
+ u32 lcdc_type;
+ struct rk_lcdc_driver *lcdc_dev = NULL;
printk(KERN_DEBUG pr_fmt("In func %s,freq=%dMHz\n"), __func__, n_mhz);
- if (scpi_ddr_set_clk_rate(n_mhz))
+ lcdc_dev = rk_get_lcdc_drv("lcdc0");
+ lcdc_type = lcdc_dev ? (u32)lcdc_dev->cur_screen->type : 0;
+ printk(KERN_DEBUG pr_fmt("lcdc type:%d\n"), lcdc_type);
+ if (scpi_ddr_set_clk_rate(n_mhz, lcdc_type))
pr_info("set ddr freq timeout\n");
- ret = scpi_ddr_get_clk_rate();
+ ret = _ddr_recalc_rate() / 1000000;
printk(KERN_DEBUG pr_fmt("Func %s out,freq=%dMHz\n"), __func__, ret);
return ret;
}
return (n_mhz / 12) * 12;
}
-static int _ddr_recalc_rate(void)
-{
- return (1000000 * scpi_ddr_get_clk_rate());
-}
-
static void _ddr_set_auto_self_refresh(bool en)
{
if (scpi_ddr_set_auto_self_refresh(en))
ddr_monitor_start();
}
-static void ddr_init(u32 dram_speed_bin, u32 freq)
+static void ddr_init(u32 dram_speed_bin, u32 freq, u32 addr_mcu_el3)
{
- printk(KERN_DEBUG pr_fmt("In Func:%s,dram_speed_bin:%d,freq:%d\n"),
- __func__, dram_speed_bin, freq);
- if (scpi_ddr_init(dram_speed_bin, freq))
+ int lcdc_type;
+ static u32 addr = 0;
+
+ struct rk_lcdc_driver *lcdc_dev = NULL;
+
+ if (addr == 0)
+ addr = addr_mcu_el3;
+
+ lcdc_dev = rk_get_lcdc_drv("lcdc0");
+ if (lcdc_dev == NULL)
+ lcdc_type = 0;
+ else
+ lcdc_type = (u32)lcdc_dev->cur_screen->type;
+ printk(KERN_DEBUG pr_fmt("In Func:%s,dram_speed_bin:%d,freq:%d,lcdc_type:%d\n"),
+ __func__, dram_speed_bin, freq, lcdc_type);
+ if (scpi_ddr_init(dram_speed_bin, freq, lcdc_type, addr))
pr_info("ddr init error\n");
else
printk(KERN_DEBUG pr_fmt("%s out\n"), __func__);
}
+static int ddr_init_resume(struct platform_device *pdev)
+{
+ ddr_init(DDR3_DEFAULT, 0, 0);
+ return 0;
+}
+#define RKTF_VER_MAJOR(ver) (((ver) >> 16) & 0xffff)
+#define RKTF_VER_MINOR(ver) ((ver) & 0xffff)
+/* valid ver */
+#define RKTF_VLDVER_MAJOR (1)
+#define RKTF_VLDVER_MINOR (5)
+
+static int __init rockchip_tf_ver_check(void)
+{
+ u32 version;
+
+ version = rockchip_psci_smc_get_tf_ver();
+ if (((RKTF_VER_MAJOR(version) == RKTF_VLDVER_MAJOR) &&
+ (RKTF_VER_MINOR(version) >= RKTF_VLDVER_MINOR)) ||
+ (RKTF_VER_MAJOR(version) > RKTF_VLDVER_MAJOR))
+ return 0;
+
+ pr_err("read tf version 0x%x!\n", version);
+
+ do {
+ mdelay(1000);
+ pr_err("trusted firmware need to update to(%d.%d) or is invaild!\n",
+ RKTF_VLDVER_MAJOR, RKTF_VLDVER_MINOR);
+ } while (1);
+
+ return 0;
+}
+
+
static int __init rockchip_ddr_probe(struct platform_device *pdev)
{
+ u32 addr_mcu_el3;
struct device_node *np;
+ pr_info("Rockchip DDR Initialize, verision: "DDR_VERSION"\n");
np = pdev->dev.of_node;
ddr_data =
devm_kzalloc(&pdev->dev, sizeof(struct rockchip_ddr), GFP_KERNEL);
ddr_set_auto_self_refresh = _ddr_set_auto_self_refresh;
ddr_bandwidth_get = _ddr_bandwidth_get;
ddr_recalc_rate = _ddr_recalc_rate;
- ddr_init(DDR3_DEFAULT, 0);
+ rockchip_tf_ver_check();
+ if (!of_do_get_timings(np, (struct ddr_timing *)&ddr_data->dram_timing)) {
+ if (scpi_ddr_send_timing((u32 *)&ddr_data->dram_timing,
+ sizeof(struct ddr_timing)))
+ pr_info("send ddr timing timeout\n");
+ } else {
+ pr_err("get ddr timing from dts error\n");
+ ddr_data->dram_timing.dram_spd_bin = DDR3_DEFAULT;
+ }
+ addr_mcu_el3 = rockchip_psci_smc_write(PSCI_SIP_EL3FIQ_CFG,
+ FIQ_NUM_FOR_DCF,
+ FIQ_CPU_TGT_BOOT, 0);
+ if ((addr_mcu_el3 == 0) || (addr_mcu_el3 > 0x80000))
+ pr_info("Trust version error, pls check trust version\n");
+ ddr_init(ddr_data->dram_timing.dram_spd_bin, 0, addr_mcu_el3);
pr_info("%s: success\n", __func__);
return 0;
}
};
static struct platform_driver rockchip_ddr_driver = {
+#ifdef CONFIG_PM
+ .resume = ddr_init_resume,
+#endif /* CONFIG_PM */
.driver = {
.name = "rockchip_ddr",
.of_match_table = rockchip_ddr_of_match,
static int __init rockchip_ddr_init(void)
{
- pr_info("rockchip_ddr_init\n");
return platform_driver_probe(&rockchip_ddr_driver, rockchip_ddr_probe);
}