/*
* Copyright (c) 2016 Rockchip Electronics Co., Ltd
*/
+#include <common.h>
+#include <dm.h>
+#include <env.h>
+#include <clk.h>
+#include <init.h>
+#include <asm/armv7.h>
#include <asm/io.h>
+#include <asm/arch-rockchip/bootrom.h>
+#include <asm/arch-rockchip/clock.h>
+#include <asm/arch-rockchip/cru.h>
#include <asm/arch-rockchip/hardware.h>
#include <asm/arch-rockchip/grf_rk3288.h>
+#include <asm/arch-rockchip/pmu_rk3288.h>
+#include <asm/arch-rockchip/qos_rk3288.h>
+#include <asm/arch-rockchip/sdram.h>
+
+DECLARE_GLOBAL_DATA_PTR;
#define GRF_BASE 0xff770000
+const char * const boot_devices[BROM_LAST_BOOTSOURCE + 1] = {
+ [BROM_BOOTSOURCE_EMMC] = "/dwmmc@ff0f0000",
+ [BROM_BOOTSOURCE_SD] = "/dwmmc@ff0c0000",
+};
+
+#ifdef CONFIG_SPL_BUILD
+static void configure_l2ctlr(void)
+{
+ u32 l2ctlr;
+
+ l2ctlr = read_l2ctlr();
+ l2ctlr &= 0xfffc0000; /* clear bit0~bit17 */
+
+ /*
+ * Data RAM write latency: 2 cycles
+ * Data RAM read latency: 2 cycles
+ * Data RAM setup latency: 1 cycle
+ * Tag RAM write latency: 1 cycle
+ * Tag RAM read latency: 1 cycle
+ * Tag RAM setup latency: 1 cycle
+ */
+ l2ctlr |= (1 << 3 | 1 << 0);
+ write_l2ctlr(l2ctlr);
+}
+#endif
+
+int rk3288_qos_init(void)
+{
+ int val = 2 << PRIORITY_HIGH_SHIFT | 2 << PRIORITY_LOW_SHIFT;
+ /* set vop qos to higher priority */
+ writel(val, CPU_AXI_QOS_PRIORITY + VIO0_VOP_QOS);
+ writel(val, CPU_AXI_QOS_PRIORITY + VIO1_VOP_QOS);
+
+ if (!fdt_node_check_compatible(gd->fdt_blob, 0,
+ "rockchip,rk3288-tinker")) {
+ /* set isp qos to higher priority */
+ writel(val, CPU_AXI_QOS_PRIORITY + VIO1_ISP_R_QOS);
+ writel(val, CPU_AXI_QOS_PRIORITY + VIO1_ISP_W0_QOS);
+ writel(val, CPU_AXI_QOS_PRIORITY + VIO1_ISP_W1_QOS);
+ }
+
+ return 0;
+}
+
int arch_cpu_init(void)
{
+#ifdef CONFIG_SPL_BUILD
+ configure_l2ctlr();
+#else
/* We do some SoC one time setting here. */
struct rk3288_grf * const grf = (void *)GRF_BASE;
/* Use rkpwm by default */
rk_setreg(&grf->soc_con2, 1 << 0);
+ /*
+ * Disable JTAG on sdmmc0 IO. The SDMMC won't work until this bit is
+ * cleared
+ */
+ rk_clrreg(&grf->soc_con0, 1 << 12);
+
+ rk3288_qos_init();
+#endif
+
return 0;
}
GPIO7C6_UART2DBG_SIN << GPIO7C6_SHIFT);
}
#endif
+
+static void rk3288_detect_reset_reason(void)
+{
+ struct rockchip_cru *cru = rockchip_get_cru();
+ const char *reason;
+
+ if (IS_ERR(cru))
+ return;
+
+ switch (cru->cru_glb_rst_st) {
+ case GLB_POR_RST:
+ reason = "POR";
+ break;
+ case FST_GLB_RST_ST:
+ case SND_GLB_RST_ST:
+ reason = "RST";
+ break;
+ case FST_GLB_TSADC_RST_ST:
+ case SND_GLB_TSADC_RST_ST:
+ reason = "THERMAL";
+ break;
+ case FST_GLB_WDT_RST_ST:
+ case SND_GLB_WDT_RST_ST:
+ reason = "WDOG";
+ break;
+ default:
+ reason = "unknown reset";
+ }
+
+ env_set("reset_reason", reason);
+
+ /*
+ * Clear cru_glb_rst_st, so we can determine the last reset cause
+ * for following resets.
+ */
+ rk_clrreg(&cru->cru_glb_rst_st, GLB_RST_ST_MASK);
+}
+
+__weak int rk3288_board_late_init(void)
+{
+ return 0;
+}
+
+int rk_board_late_init(void)
+{
+ rk3288_detect_reset_reason();
+
+ return rk3288_board_late_init();
+}
+
+static int do_clock(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ static const struct {
+ char *name;
+ int id;
+ } clks[] = {
+ { "osc", CLK_OSC },
+ { "apll", CLK_ARM },
+ { "dpll", CLK_DDR },
+ { "cpll", CLK_CODEC },
+ { "gpll", CLK_GENERAL },
+#ifdef CONFIG_ROCKCHIP_RK3036
+ { "mpll", CLK_NEW },
+#else
+ { "npll", CLK_NEW },
+#endif
+ };
+ int ret, i;
+ struct udevice *dev;
+
+ ret = rockchip_get_clk(&dev);
+ if (ret) {
+ printf("clk-uclass not found\n");
+ return 0;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(clks); i++) {
+ struct clk clk;
+ ulong rate;
+
+ clk.id = clks[i].id;
+ ret = clk_request(dev, &clk);
+ if (ret < 0)
+ continue;
+
+ rate = clk_get_rate(&clk);
+ printf("%s: %lu\n", clks[i].name, rate);
+
+ clk_free(&clk);
+ }
+
+ return 0;
+}
+
+U_BOOT_CMD(
+ clock, 2, 1, do_clock,
+ "display information about clocks",
+ ""
+);