18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2012 Freescale Semiconductor, Inc. 48c2ecf20Sopenharmony_ci * Copyright 2012 Linaro Ltd. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/clk.h> 88c2ecf20Sopenharmony_ci#include <linux/clk/mxs.h> 98c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/err.h> 128c2ecf20Sopenharmony_ci#include <linux/gpio.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/irqchip/mxs.h> 158c2ecf20Sopenharmony_ci#include <linux/reboot.h> 168c2ecf20Sopenharmony_ci#include <linux/micrel_phy.h> 178c2ecf20Sopenharmony_ci#include <linux/of_address.h> 188c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 198c2ecf20Sopenharmony_ci#include <linux/phy.h> 208c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 218c2ecf20Sopenharmony_ci#include <linux/sys_soc.h> 228c2ecf20Sopenharmony_ci#include <asm/mach/arch.h> 238c2ecf20Sopenharmony_ci#include <asm/mach/map.h> 248c2ecf20Sopenharmony_ci#include <asm/mach/time.h> 258c2ecf20Sopenharmony_ci#include <asm/system_misc.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#include "pm.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* MXS DIGCTL SAIF CLKMUX */ 308c2ecf20Sopenharmony_ci#define MXS_DIGCTL_SAIF_CLKMUX_DIRECT 0x0 318c2ecf20Sopenharmony_ci#define MXS_DIGCTL_SAIF_CLKMUX_CROSSINPUT 0x1 328c2ecf20Sopenharmony_ci#define MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0 0x2 338c2ecf20Sopenharmony_ci#define MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR1 0x3 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define HW_DIGCTL_CHIPID 0x310 368c2ecf20Sopenharmony_ci#define HW_DIGCTL_CHIPID_MASK (0xffff << 16) 378c2ecf20Sopenharmony_ci#define HW_DIGCTL_REV_MASK 0xff 388c2ecf20Sopenharmony_ci#define HW_DIGCTL_CHIPID_MX23 (0x3780 << 16) 398c2ecf20Sopenharmony_ci#define HW_DIGCTL_CHIPID_MX28 (0x2800 << 16) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define MXS_CHIP_REVISION_1_0 0x10 428c2ecf20Sopenharmony_ci#define MXS_CHIP_REVISION_1_1 0x11 438c2ecf20Sopenharmony_ci#define MXS_CHIP_REVISION_1_2 0x12 448c2ecf20Sopenharmony_ci#define MXS_CHIP_REVISION_1_3 0x13 458c2ecf20Sopenharmony_ci#define MXS_CHIP_REVISION_1_4 0x14 468c2ecf20Sopenharmony_ci#define MXS_CHIP_REV_UNKNOWN 0xff 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define MXS_GPIO_NR(bank, nr) ((bank) * 32 + (nr)) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define MXS_SET_ADDR 0x4 518c2ecf20Sopenharmony_ci#define MXS_CLR_ADDR 0x8 528c2ecf20Sopenharmony_ci#define MXS_TOG_ADDR 0xc 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic u32 chipid; 558c2ecf20Sopenharmony_cistatic u32 socid; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic void __iomem *reset_addr; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic inline void __mxs_setl(u32 mask, void __iomem *reg) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci __raw_writel(mask, reg + MXS_SET_ADDR); 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic inline void __mxs_clrl(u32 mask, void __iomem *reg) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci __raw_writel(mask, reg + MXS_CLR_ADDR); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic inline void __mxs_togl(u32 mask, void __iomem *reg) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci __raw_writel(mask, reg + MXS_TOG_ADDR); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define OCOTP_WORD_OFFSET 0x20 758c2ecf20Sopenharmony_ci#define OCOTP_WORD_COUNT 0x20 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define BM_OCOTP_CTRL_BUSY (1 << 8) 788c2ecf20Sopenharmony_ci#define BM_OCOTP_CTRL_ERROR (1 << 9) 798c2ecf20Sopenharmony_ci#define BM_OCOTP_CTRL_RD_BANK_OPEN (1 << 12) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ocotp_mutex); 828c2ecf20Sopenharmony_cistatic u32 ocotp_words[OCOTP_WORD_COUNT]; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic const u32 *mxs_get_ocotp(void) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct device_node *np; 878c2ecf20Sopenharmony_ci void __iomem *ocotp_base; 888c2ecf20Sopenharmony_ci int timeout = 0x400; 898c2ecf20Sopenharmony_ci size_t i; 908c2ecf20Sopenharmony_ci static int once; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (once) 938c2ecf20Sopenharmony_ci return ocotp_words; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,ocotp"); 968c2ecf20Sopenharmony_ci ocotp_base = of_iomap(np, 0); 978c2ecf20Sopenharmony_ci WARN_ON(!ocotp_base); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci mutex_lock(&ocotp_mutex); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* 1028c2ecf20Sopenharmony_ci * clk_enable(hbus_clk) for ocotp can be skipped 1038c2ecf20Sopenharmony_ci * as it must be on when system is running. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* try to clear ERROR bit */ 1078c2ecf20Sopenharmony_ci __mxs_clrl(BM_OCOTP_CTRL_ERROR, ocotp_base); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* check both BUSY and ERROR cleared */ 1108c2ecf20Sopenharmony_ci while ((__raw_readl(ocotp_base) & 1118c2ecf20Sopenharmony_ci (BM_OCOTP_CTRL_BUSY | BM_OCOTP_CTRL_ERROR)) && --timeout) 1128c2ecf20Sopenharmony_ci cpu_relax(); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (unlikely(!timeout)) 1158c2ecf20Sopenharmony_ci goto error_unlock; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* open OCOTP banks for read */ 1188c2ecf20Sopenharmony_ci __mxs_setl(BM_OCOTP_CTRL_RD_BANK_OPEN, ocotp_base); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* approximately wait 32 hclk cycles */ 1218c2ecf20Sopenharmony_ci udelay(1); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* poll BUSY bit becoming cleared */ 1248c2ecf20Sopenharmony_ci timeout = 0x400; 1258c2ecf20Sopenharmony_ci while ((__raw_readl(ocotp_base) & BM_OCOTP_CTRL_BUSY) && --timeout) 1268c2ecf20Sopenharmony_ci cpu_relax(); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (unlikely(!timeout)) 1298c2ecf20Sopenharmony_ci goto error_unlock; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci for (i = 0; i < OCOTP_WORD_COUNT; i++) 1328c2ecf20Sopenharmony_ci ocotp_words[i] = __raw_readl(ocotp_base + OCOTP_WORD_OFFSET + 1338c2ecf20Sopenharmony_ci i * 0x10); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* close banks for power saving */ 1368c2ecf20Sopenharmony_ci __mxs_clrl(BM_OCOTP_CTRL_RD_BANK_OPEN, ocotp_base); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci once = 1; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci mutex_unlock(&ocotp_mutex); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return ocotp_words; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cierror_unlock: 1458c2ecf20Sopenharmony_ci mutex_unlock(&ocotp_mutex); 1468c2ecf20Sopenharmony_ci pr_err("%s: timeout in reading OCOTP\n", __func__); 1478c2ecf20Sopenharmony_ci return NULL; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cienum mac_oui { 1518c2ecf20Sopenharmony_ci OUI_FSL, 1528c2ecf20Sopenharmony_ci OUI_DENX, 1538c2ecf20Sopenharmony_ci OUI_CRYSTALFONTZ, 1548c2ecf20Sopenharmony_ci OUI_I2SE, 1558c2ecf20Sopenharmony_ci OUI_ARMADEUS, 1568c2ecf20Sopenharmony_ci}; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void __init update_fec_mac_prop(enum mac_oui oui) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct device_node *np, *from = NULL; 1618c2ecf20Sopenharmony_ci struct property *newmac; 1628c2ecf20Sopenharmony_ci const u32 *ocotp = mxs_get_ocotp(); 1638c2ecf20Sopenharmony_ci u8 *macaddr; 1648c2ecf20Sopenharmony_ci u32 val; 1658c2ecf20Sopenharmony_ci int i; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci for (i = 0; i < 2; i++) { 1688c2ecf20Sopenharmony_ci np = of_find_compatible_node(from, NULL, "fsl,imx28-fec"); 1698c2ecf20Sopenharmony_ci if (!np) 1708c2ecf20Sopenharmony_ci return; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci from = np; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (of_get_property(np, "local-mac-address", NULL)) 1758c2ecf20Sopenharmony_ci continue; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci newmac = kzalloc(sizeof(*newmac) + 6, GFP_KERNEL); 1788c2ecf20Sopenharmony_ci if (!newmac) 1798c2ecf20Sopenharmony_ci return; 1808c2ecf20Sopenharmony_ci newmac->value = newmac + 1; 1818c2ecf20Sopenharmony_ci newmac->length = 6; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci newmac->name = kstrdup("local-mac-address", GFP_KERNEL); 1848c2ecf20Sopenharmony_ci if (!newmac->name) { 1858c2ecf20Sopenharmony_ci kfree(newmac); 1868c2ecf20Sopenharmony_ci return; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci /* 1908c2ecf20Sopenharmony_ci * OCOTP only stores the last 4 octets for each mac address, 1918c2ecf20Sopenharmony_ci * so hard-code OUI here. 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ci macaddr = newmac->value; 1948c2ecf20Sopenharmony_ci switch (oui) { 1958c2ecf20Sopenharmony_ci case OUI_FSL: 1968c2ecf20Sopenharmony_ci macaddr[0] = 0x00; 1978c2ecf20Sopenharmony_ci macaddr[1] = 0x04; 1988c2ecf20Sopenharmony_ci macaddr[2] = 0x9f; 1998c2ecf20Sopenharmony_ci break; 2008c2ecf20Sopenharmony_ci case OUI_DENX: 2018c2ecf20Sopenharmony_ci macaddr[0] = 0xc0; 2028c2ecf20Sopenharmony_ci macaddr[1] = 0xe5; 2038c2ecf20Sopenharmony_ci macaddr[2] = 0x4e; 2048c2ecf20Sopenharmony_ci break; 2058c2ecf20Sopenharmony_ci case OUI_CRYSTALFONTZ: 2068c2ecf20Sopenharmony_ci macaddr[0] = 0x58; 2078c2ecf20Sopenharmony_ci macaddr[1] = 0xb9; 2088c2ecf20Sopenharmony_ci macaddr[2] = 0xe1; 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci case OUI_I2SE: 2118c2ecf20Sopenharmony_ci macaddr[0] = 0x00; 2128c2ecf20Sopenharmony_ci macaddr[1] = 0x01; 2138c2ecf20Sopenharmony_ci macaddr[2] = 0x87; 2148c2ecf20Sopenharmony_ci break; 2158c2ecf20Sopenharmony_ci case OUI_ARMADEUS: 2168c2ecf20Sopenharmony_ci macaddr[0] = 0x00; 2178c2ecf20Sopenharmony_ci macaddr[1] = 0x1e; 2188c2ecf20Sopenharmony_ci macaddr[2] = 0xac; 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci val = ocotp[i]; 2228c2ecf20Sopenharmony_ci macaddr[3] = (val >> 16) & 0xff; 2238c2ecf20Sopenharmony_ci macaddr[4] = (val >> 8) & 0xff; 2248c2ecf20Sopenharmony_ci macaddr[5] = (val >> 0) & 0xff; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci of_update_property(np, newmac); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic inline void enable_clk_enet_out(void) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci struct clk *clk = clk_get_sys("enet_out", NULL); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (!IS_ERR(clk)) 2358c2ecf20Sopenharmony_ci clk_prepare_enable(clk); 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic void __init imx28_evk_init(void) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci update_fec_mac_prop(OUI_FSL); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void __init imx28_apf28_init(void) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci update_fec_mac_prop(OUI_ARMADEUS); 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int apx4devkit_phy_fixup(struct phy_device *phy) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci phy->dev_flags |= MICREL_PHY_50MHZ_CLK; 2538c2ecf20Sopenharmony_ci return 0; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic void __init apx4devkit_init(void) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci enable_clk_enet_out(); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (IS_BUILTIN(CONFIG_PHYLIB)) 2618c2ecf20Sopenharmony_ci phy_register_fixup_for_uid(PHY_ID_KSZ8051, MICREL_PHY_ID_MASK, 2628c2ecf20Sopenharmony_ci apx4devkit_phy_fixup); 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic void __init crystalfontz_init(void) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci update_fec_mac_prop(OUI_CRYSTALFONTZ); 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void __init duckbill_init(void) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci update_fec_mac_prop(OUI_I2SE); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void __init m28cu3_init(void) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci update_fec_mac_prop(OUI_DENX); 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic const char __init *mxs_get_soc_id(void) 2818c2ecf20Sopenharmony_ci{ 2828c2ecf20Sopenharmony_ci struct device_node *np; 2838c2ecf20Sopenharmony_ci void __iomem *digctl_base; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,imx23-digctl"); 2868c2ecf20Sopenharmony_ci digctl_base = of_iomap(np, 0); 2878c2ecf20Sopenharmony_ci WARN_ON(!digctl_base); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci chipid = readl(digctl_base + HW_DIGCTL_CHIPID); 2908c2ecf20Sopenharmony_ci socid = chipid & HW_DIGCTL_CHIPID_MASK; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci iounmap(digctl_base); 2938c2ecf20Sopenharmony_ci of_node_put(np); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci switch (socid) { 2968c2ecf20Sopenharmony_ci case HW_DIGCTL_CHIPID_MX23: 2978c2ecf20Sopenharmony_ci return "i.MX23"; 2988c2ecf20Sopenharmony_ci case HW_DIGCTL_CHIPID_MX28: 2998c2ecf20Sopenharmony_ci return "i.MX28"; 3008c2ecf20Sopenharmony_ci default: 3018c2ecf20Sopenharmony_ci return "Unknown"; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic u32 __init mxs_get_cpu_rev(void) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci u32 rev = chipid & HW_DIGCTL_REV_MASK; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci switch (socid) { 3108c2ecf20Sopenharmony_ci case HW_DIGCTL_CHIPID_MX23: 3118c2ecf20Sopenharmony_ci switch (rev) { 3128c2ecf20Sopenharmony_ci case 0x0: 3138c2ecf20Sopenharmony_ci return MXS_CHIP_REVISION_1_0; 3148c2ecf20Sopenharmony_ci case 0x1: 3158c2ecf20Sopenharmony_ci return MXS_CHIP_REVISION_1_1; 3168c2ecf20Sopenharmony_ci case 0x2: 3178c2ecf20Sopenharmony_ci return MXS_CHIP_REVISION_1_2; 3188c2ecf20Sopenharmony_ci case 0x3: 3198c2ecf20Sopenharmony_ci return MXS_CHIP_REVISION_1_3; 3208c2ecf20Sopenharmony_ci case 0x4: 3218c2ecf20Sopenharmony_ci return MXS_CHIP_REVISION_1_4; 3228c2ecf20Sopenharmony_ci default: 3238c2ecf20Sopenharmony_ci return MXS_CHIP_REV_UNKNOWN; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci case HW_DIGCTL_CHIPID_MX28: 3268c2ecf20Sopenharmony_ci switch (rev) { 3278c2ecf20Sopenharmony_ci case 0x0: 3288c2ecf20Sopenharmony_ci return MXS_CHIP_REVISION_1_1; 3298c2ecf20Sopenharmony_ci case 0x1: 3308c2ecf20Sopenharmony_ci return MXS_CHIP_REVISION_1_2; 3318c2ecf20Sopenharmony_ci default: 3328c2ecf20Sopenharmony_ci return MXS_CHIP_REV_UNKNOWN; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci default: 3358c2ecf20Sopenharmony_ci return MXS_CHIP_REV_UNKNOWN; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci} 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_cistatic const char __init *mxs_get_revision(void) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci u32 rev = mxs_get_cpu_rev(); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (rev != MXS_CHIP_REV_UNKNOWN) 3448c2ecf20Sopenharmony_ci return kasprintf(GFP_KERNEL, "%d.%d", (rev >> 4) & 0xf, 3458c2ecf20Sopenharmony_ci rev & 0xf); 3468c2ecf20Sopenharmony_ci else 3478c2ecf20Sopenharmony_ci return kasprintf(GFP_KERNEL, "%s", "Unknown"); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci#define MX23_CLKCTRL_RESET_OFFSET 0x120 3518c2ecf20Sopenharmony_ci#define MX28_CLKCTRL_RESET_OFFSET 0x1e0 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic int __init mxs_restart_init(void) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct device_node *np; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,clkctrl"); 3588c2ecf20Sopenharmony_ci reset_addr = of_iomap(np, 0); 3598c2ecf20Sopenharmony_ci if (!reset_addr) 3608c2ecf20Sopenharmony_ci return -ENODEV; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (of_device_is_compatible(np, "fsl,imx23-clkctrl")) 3638c2ecf20Sopenharmony_ci reset_addr += MX23_CLKCTRL_RESET_OFFSET; 3648c2ecf20Sopenharmony_ci else 3658c2ecf20Sopenharmony_ci reset_addr += MX28_CLKCTRL_RESET_OFFSET; 3668c2ecf20Sopenharmony_ci of_node_put(np); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic void __init eukrea_mbmx283lc_init(void) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci mxs_saif_clkmux_select(MXS_DIGCTL_SAIF_CLKMUX_EXTMSTR0); 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic void __init mxs_machine_init(void) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct device_node *root; 3798c2ecf20Sopenharmony_ci struct device *parent; 3808c2ecf20Sopenharmony_ci struct soc_device *soc_dev; 3818c2ecf20Sopenharmony_ci struct soc_device_attribute *soc_dev_attr; 3828c2ecf20Sopenharmony_ci int ret; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 3858c2ecf20Sopenharmony_ci if (!soc_dev_attr) 3868c2ecf20Sopenharmony_ci return; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci root = of_find_node_by_path("/"); 3898c2ecf20Sopenharmony_ci ret = of_property_read_string(root, "model", &soc_dev_attr->machine); 3908c2ecf20Sopenharmony_ci if (ret) { 3918c2ecf20Sopenharmony_ci kfree(soc_dev_attr); 3928c2ecf20Sopenharmony_ci return; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci soc_dev_attr->family = "Freescale MXS Family"; 3968c2ecf20Sopenharmony_ci soc_dev_attr->soc_id = mxs_get_soc_id(); 3978c2ecf20Sopenharmony_ci soc_dev_attr->revision = mxs_get_revision(); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci soc_dev = soc_device_register(soc_dev_attr); 4008c2ecf20Sopenharmony_ci if (IS_ERR(soc_dev)) { 4018c2ecf20Sopenharmony_ci kfree(soc_dev_attr->revision); 4028c2ecf20Sopenharmony_ci kfree(soc_dev_attr); 4038c2ecf20Sopenharmony_ci return; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci parent = soc_device_to_device(soc_dev); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (of_machine_is_compatible("fsl,imx28-evk")) 4098c2ecf20Sopenharmony_ci imx28_evk_init(); 4108c2ecf20Sopenharmony_ci if (of_machine_is_compatible("armadeus,imx28-apf28")) 4118c2ecf20Sopenharmony_ci imx28_apf28_init(); 4128c2ecf20Sopenharmony_ci else if (of_machine_is_compatible("bluegiga,apx4devkit")) 4138c2ecf20Sopenharmony_ci apx4devkit_init(); 4148c2ecf20Sopenharmony_ci else if (of_machine_is_compatible("crystalfontz,cfa10036")) 4158c2ecf20Sopenharmony_ci crystalfontz_init(); 4168c2ecf20Sopenharmony_ci else if (of_machine_is_compatible("eukrea,mbmx283lc")) 4178c2ecf20Sopenharmony_ci eukrea_mbmx283lc_init(); 4188c2ecf20Sopenharmony_ci else if (of_machine_is_compatible("i2se,duckbill") || 4198c2ecf20Sopenharmony_ci of_machine_is_compatible("i2se,duckbill-2")) 4208c2ecf20Sopenharmony_ci duckbill_init(); 4218c2ecf20Sopenharmony_ci else if (of_machine_is_compatible("msr,m28cu3")) 4228c2ecf20Sopenharmony_ci m28cu3_init(); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci of_platform_default_populate(NULL, NULL, parent); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci mxs_restart_init(); 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci#define MXS_CLKCTRL_RESET_CHIP (1 << 1) 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci/* 4328c2ecf20Sopenharmony_ci * Reset the system. It is called by machine_restart(). 4338c2ecf20Sopenharmony_ci */ 4348c2ecf20Sopenharmony_cistatic void mxs_restart(enum reboot_mode mode, const char *cmd) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci if (reset_addr) { 4378c2ecf20Sopenharmony_ci /* reset the chip */ 4388c2ecf20Sopenharmony_ci __mxs_setl(MXS_CLKCTRL_RESET_CHIP, reset_addr); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci pr_err("Failed to assert the chip reset\n"); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* Delay to allow the serial port to show the message */ 4438c2ecf20Sopenharmony_ci mdelay(50); 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* We'll take a jump through zero as a poor second */ 4478c2ecf20Sopenharmony_ci soft_restart(0); 4488c2ecf20Sopenharmony_ci} 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic const char *const mxs_dt_compat[] __initconst = { 4518c2ecf20Sopenharmony_ci "fsl,imx28", 4528c2ecf20Sopenharmony_ci "fsl,imx23", 4538c2ecf20Sopenharmony_ci NULL, 4548c2ecf20Sopenharmony_ci}; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ciDT_MACHINE_START(MXS, "Freescale MXS (Device Tree)") 4578c2ecf20Sopenharmony_ci .handle_irq = icoll_handle_irq, 4588c2ecf20Sopenharmony_ci .init_machine = mxs_machine_init, 4598c2ecf20Sopenharmony_ci .init_late = mxs_pm_init, 4608c2ecf20Sopenharmony_ci .dt_compat = mxs_dt_compat, 4618c2ecf20Sopenharmony_ci .restart = mxs_restart, 4628c2ecf20Sopenharmony_ciMACHINE_END 463