/* * Copyright (C) 2017 Rockchip Electronics Co., Ltd. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. */ #include #include #include #include #include #include #include #include #include unsigned long rockchip_soc_id; EXPORT_SYMBOL(rockchip_soc_id); static int rockchip_cpuinfo_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct nvmem_cell *cell; unsigned char *efuse_buf, buf[16]; size_t len = 0; int i; cell = nvmem_cell_get(dev, "cpu-code"); if (!IS_ERR(cell)) { efuse_buf = nvmem_cell_read(cell, &len); nvmem_cell_put(cell); if (IS_ERR(efuse_buf)) return PTR_ERR(efuse_buf); if (len == 2) rockchip_set_cpu((efuse_buf[0] << 8 | efuse_buf[1])); kfree(efuse_buf); } cell = nvmem_cell_get(dev, "cpu-version"); if (!IS_ERR(cell)) { efuse_buf = nvmem_cell_read(cell, &len); nvmem_cell_put(cell); if (IS_ERR(efuse_buf)) return PTR_ERR(efuse_buf); if ((len == 1) && (efuse_buf[0] > rockchip_get_cpu_version())) rockchip_set_cpu_version(efuse_buf[0]); kfree(efuse_buf); } cell = nvmem_cell_get(dev, "id"); if (IS_ERR(cell)) return dev_err_probe(dev, PTR_ERR(cell), "failed to get id cell\n"); efuse_buf = nvmem_cell_read(cell, &len); nvmem_cell_put(cell); if (IS_ERR(efuse_buf)) return PTR_ERR(efuse_buf); if (len != 16) { kfree(efuse_buf); dev_err(dev, "invalid id len: %zu\n", len); return -EINVAL; } for (i = 0; i < 8; i++) { buf[i] = efuse_buf[1 + (i << 1)]; buf[i + 8] = efuse_buf[i << 1]; } kfree(efuse_buf); dev_info(dev, "SoC\t\t: %lx\n", rockchip_soc_id); #ifdef CONFIG_NO_GKI system_serial_low = crc32(0, buf, 8); system_serial_high = crc32(system_serial_low, buf + 8, 8); dev_info(dev, "Serial\t\t: %08x%08x\n", system_serial_high, system_serial_low); #endif return 0; } static const struct of_device_id rockchip_cpuinfo_of_match[] = { { .compatible = "rockchip,cpuinfo", }, { }, }; MODULE_DEVICE_TABLE(of, rockchip_cpuinfo_of_match); static struct platform_driver rockchip_cpuinfo_driver = { .probe = rockchip_cpuinfo_probe, .driver = { .name = "rockchip-cpuinfo", .of_match_table = rockchip_cpuinfo_of_match, }, }; static void rockchip_set_cpu_version_from_os_reg(u32 reg) { void __iomem *r = ioremap(reg, 0x4); if (r) { rockchip_set_cpu_version(readl_relaxed(r) & GENMASK(2, 0)); iounmap(r); } } static void px30_init(void) { void __iomem *base; rockchip_soc_id = ROCKCHIP_SOC_PX30; #define PX30_DDR_GRF_BASE 0xFF630000 #define PX30_DDR_GRF_CON1 0x04 base = ioremap(PX30_DDR_GRF_BASE, SZ_4K); if (base) { unsigned int val = readl_relaxed(base + PX30_DDR_GRF_CON1); if (((val >> 14) & 0x03) == 0x03) rockchip_soc_id = ROCKCHIP_SOC_PX30S; iounmap(base); } } #define RV1106_OS_REG1 0xff020204 static void rv1103_init(void) { rockchip_soc_id = ROCKCHIP_SOC_RV1103; rockchip_set_cpu_version_from_os_reg(RV1106_OS_REG1); } static void rv1106_init(void) { rockchip_soc_id = ROCKCHIP_SOC_RV1106; rockchip_set_cpu_version_from_os_reg(RV1106_OS_REG1); } static void rv1109_init(void) { rockchip_soc_id = ROCKCHIP_SOC_RV1109; } static void rv1126_init(void) { rockchip_soc_id = ROCKCHIP_SOC_RV1126; } static void rk3288_init(void) { void __iomem *base; rockchip_soc_id = ROCKCHIP_SOC_RK3288; #define RK3288_HDMI_PHYS 0xFF980000 base = ioremap(RK3288_HDMI_PHYS, SZ_4K); if (base) { /* RK3288W HDMI Revision ID is 0x1A */ if (readl_relaxed(base + 4) == 0x1A) rockchip_soc_id = ROCKCHIP_SOC_RK3288W; iounmap(base); } } static void rk3126_init(void) { void __iomem *base; rockchip_soc_id = ROCKCHIP_SOC_RK3126; #define RK312X_GRF_PHYS 0x20008000 #define RK312X_GRF_SOC_CON1 0x00000144 #define RK312X_GRF_CHIP_TAG 0x00000300 base = ioremap(RK312X_GRF_PHYS, SZ_4K); if (base) { if (readl_relaxed(base + RK312X_GRF_CHIP_TAG) == 0x3136) { if (readl_relaxed(base + RK312X_GRF_SOC_CON1) & 0x1) rockchip_soc_id = ROCKCHIP_SOC_RK3126C; else rockchip_soc_id = ROCKCHIP_SOC_RK3126B; } iounmap(base); } } static void rk3308_init(void) { void __iomem *base; rockchip_soc_id = ROCKCHIP_SOC_RK3308; #define RK3308_GRF_PHYS 0xFF000000 #define RK3308_GRF_CHIP_ID 0x800 base = ioremap(RK3308_GRF_PHYS, SZ_4K); if (base) { u32 v = readl_relaxed(base + RK3308_GRF_CHIP_ID); if (v == 0x3308) rockchip_soc_id = ROCKCHIP_SOC_RK3308B; if (v == 0x3308c) rockchip_soc_id = ROCKCHIP_SOC_RK3308BS; iounmap(base); } } static void rk3528_init(void) { if (of_machine_is_compatible("rockchip,rk3528")) rockchip_soc_id = ROCKCHIP_SOC_RK3528; else if (of_machine_is_compatible("rockchip,rk3528a")) rockchip_soc_id = ROCKCHIP_SOC_RK3528A; } #define RK356X_PMU_GRF_PHYS 0xfdc20000 #define RK356X_PMU_GRF_SOC_CON0 0x00000100 #define RK356X_CHIP_VERSION_MASK 0x00008000 static void rk356x_set_cpu_version(void) { void __iomem *base; base = ioremap(RK356X_PMU_GRF_PHYS, SZ_4K); if (base) { if (readl_relaxed(base + RK356X_PMU_GRF_SOC_CON0) & RK356X_CHIP_VERSION_MASK) rockchip_set_cpu_version(1); iounmap(base); } } static void rk3566_init(void) { rockchip_soc_id = ROCKCHIP_SOC_RK3566; rk356x_set_cpu_version(); } static void rk3567_init(void) { rockchip_soc_id = ROCKCHIP_SOC_RK3567; rk356x_set_cpu_version(); } static void rk3568_init(void) { rockchip_soc_id = ROCKCHIP_SOC_RK3568; rk356x_set_cpu_version(); } int rockchip_soc_id_init(void) { if (rockchip_soc_id) return 0; if (cpu_is_rk3288()) { rk3288_init(); } else if (cpu_is_rk312x()) { if (of_machine_is_compatible("rockchip,rk3128")) rockchip_soc_id = ROCKCHIP_SOC_RK3128; else rk3126_init(); } else if (cpu_is_rk3308()) { rk3308_init(); } else if (cpu_is_rv1103()) { rv1103_init(); } else if (cpu_is_rv1106()) { rv1106_init(); } else if (cpu_is_rv1109()) { rv1109_init(); } else if (cpu_is_rv1126()) { rv1126_init(); } else if (cpu_is_rk3528()) { rk3528_init(); } else if (cpu_is_rk3566()) { rk3566_init(); } else if (cpu_is_rk3567()) { rk3567_init(); } else if (cpu_is_rk3568()) { rk3568_init(); } else if (cpu_is_px30()) { px30_init(); } return 0; } EXPORT_SYMBOL(rockchip_soc_id_init); #ifndef MODULE pure_initcall(rockchip_soc_id_init); #endif static int __init rockchip_cpuinfo_init(void) { #ifdef MODULE rockchip_soc_id_init(); #endif return platform_driver_register(&rockchip_cpuinfo_driver); } subsys_initcall_sync(rockchip_cpuinfo_init); static void __exit rockchip_cpuinfo_exit(void) { platform_driver_unregister(&rockchip_cpuinfo_driver); } module_exit(rockchip_cpuinfo_exit); MODULE_LICENSE("GPL");