18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Based on linux/arch/mips/txx9/rbtx4938/setup.c, 38c2ecf20Sopenharmony_ci * and RBTX49xx patch from CELF patch archive. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * 2003-2005 (c) MontaVista Software, Inc. 68c2ecf20Sopenharmony_ci * (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 98c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 108c2ecf20Sopenharmony_ci * for more details. 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/types.h> 158c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 168c2ecf20Sopenharmony_ci#include <linux/string.h> 178c2ecf20Sopenharmony_ci#include <linux/export.h> 188c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 198c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 208c2ecf20Sopenharmony_ci#include <linux/err.h> 218c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 228c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 238c2ecf20Sopenharmony_ci#include <linux/platform_data/txx9/ndfmc.h> 248c2ecf20Sopenharmony_ci#include <linux/serial_core.h> 258c2ecf20Sopenharmony_ci#include <linux/mtd/physmap.h> 268c2ecf20Sopenharmony_ci#include <linux/leds.h> 278c2ecf20Sopenharmony_ci#include <linux/device.h> 288c2ecf20Sopenharmony_ci#include <linux/slab.h> 298c2ecf20Sopenharmony_ci#include <linux/io.h> 308c2ecf20Sopenharmony_ci#include <linux/irq.h> 318c2ecf20Sopenharmony_ci#include <asm/bootinfo.h> 328c2ecf20Sopenharmony_ci#include <asm/idle.h> 338c2ecf20Sopenharmony_ci#include <asm/time.h> 348c2ecf20Sopenharmony_ci#include <asm/reboot.h> 358c2ecf20Sopenharmony_ci#include <asm/r4kcache.h> 368c2ecf20Sopenharmony_ci#include <asm/setup.h> 378c2ecf20Sopenharmony_ci#include <asm/txx9/generic.h> 388c2ecf20Sopenharmony_ci#include <asm/txx9/pci.h> 398c2ecf20Sopenharmony_ci#include <asm/txx9tmr.h> 408c2ecf20Sopenharmony_ci#include <asm/txx9/dmac.h> 418c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_TX49XX 428c2ecf20Sopenharmony_ci#include <asm/txx9/tx4938.h> 438c2ecf20Sopenharmony_ci#endif 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* EBUSC settings of TX4927, etc. */ 468c2ecf20Sopenharmony_cistruct resource txx9_ce_res[8]; 478c2ecf20Sopenharmony_cistatic char txx9_ce_res_name[8][4]; /* "CEn" */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* pcode, internal register */ 508c2ecf20Sopenharmony_ciunsigned int txx9_pcode; 518c2ecf20Sopenharmony_cichar txx9_pcode_str[8]; 528c2ecf20Sopenharmony_cistatic struct resource txx9_reg_res = { 538c2ecf20Sopenharmony_ci .name = txx9_pcode_str, 548c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_civoid __init 578c2ecf20Sopenharmony_citxx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci int i; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(txx9_ce_res); i++) { 628c2ecf20Sopenharmony_ci sprintf(txx9_ce_res_name[i], "CE%d", i); 638c2ecf20Sopenharmony_ci txx9_ce_res[i].flags = IORESOURCE_MEM; 648c2ecf20Sopenharmony_ci txx9_ce_res[i].name = txx9_ce_res_name[i]; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci txx9_pcode = pcode; 688c2ecf20Sopenharmony_ci sprintf(txx9_pcode_str, "TX%x", pcode); 698c2ecf20Sopenharmony_ci if (base) { 708c2ecf20Sopenharmony_ci txx9_reg_res.start = base & 0xfffffffffULL; 718c2ecf20Sopenharmony_ci txx9_reg_res.end = (base & 0xfffffffffULL) + (size - 1); 728c2ecf20Sopenharmony_ci request_resource(&iomem_resource, &txx9_reg_res); 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* clocks */ 778c2ecf20Sopenharmony_ciunsigned int txx9_master_clock; 788c2ecf20Sopenharmony_ciunsigned int txx9_cpu_clock; 798c2ecf20Sopenharmony_ciunsigned int txx9_gbus_clock; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_TX39XX 828c2ecf20Sopenharmony_ci/* don't enable by default - see errata */ 838c2ecf20Sopenharmony_ciint txx9_ccfg_toeon __initdata; 848c2ecf20Sopenharmony_ci#else 858c2ecf20Sopenharmony_ciint txx9_ccfg_toeon __initdata = 1; 868c2ecf20Sopenharmony_ci#endif 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define BOARD_VEC(board) extern struct txx9_board_vec board; 898c2ecf20Sopenharmony_ci#include <asm/txx9/boards.h> 908c2ecf20Sopenharmony_ci#undef BOARD_VEC 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistruct txx9_board_vec *txx9_board_vec __initdata; 938c2ecf20Sopenharmony_cistatic char txx9_system_type[32]; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic struct txx9_board_vec *board_vecs[] __initdata = { 968c2ecf20Sopenharmony_ci#define BOARD_VEC(board) &board, 978c2ecf20Sopenharmony_ci#include <asm/txx9/boards.h> 988c2ecf20Sopenharmony_ci#undef BOARD_VEC 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic struct txx9_board_vec *__init find_board_byname(const char *name) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci int i; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* search board_vecs table */ 1068c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(board_vecs); i++) { 1078c2ecf20Sopenharmony_ci if (strstr(board_vecs[i]->system, name)) 1088c2ecf20Sopenharmony_ci return board_vecs[i]; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci return NULL; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic void __init prom_init_cmdline(void) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci int argc; 1168c2ecf20Sopenharmony_ci int *argv32; 1178c2ecf20Sopenharmony_ci int i; /* Always ignore the "-c" at argv[0] */ 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (fw_arg0 >= CKSEG0 || fw_arg1 < CKSEG0) { 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * argc is not a valid number, or argv32 is not a valid 1228c2ecf20Sopenharmony_ci * pointer 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_ci argc = 0; 1258c2ecf20Sopenharmony_ci argv32 = NULL; 1268c2ecf20Sopenharmony_ci } else { 1278c2ecf20Sopenharmony_ci argc = (int)fw_arg0; 1288c2ecf20Sopenharmony_ci argv32 = (int *)fw_arg1; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci arcs_cmdline[0] = '\0'; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci for (i = 1; i < argc; i++) { 1348c2ecf20Sopenharmony_ci char *str = (char *)(long)argv32[i]; 1358c2ecf20Sopenharmony_ci if (i != 1) 1368c2ecf20Sopenharmony_ci strcat(arcs_cmdline, " "); 1378c2ecf20Sopenharmony_ci if (strchr(str, ' ')) { 1388c2ecf20Sopenharmony_ci strcat(arcs_cmdline, "\""); 1398c2ecf20Sopenharmony_ci strcat(arcs_cmdline, str); 1408c2ecf20Sopenharmony_ci strcat(arcs_cmdline, "\""); 1418c2ecf20Sopenharmony_ci } else 1428c2ecf20Sopenharmony_ci strcat(arcs_cmdline, str); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int txx9_ic_disable __initdata; 1478c2ecf20Sopenharmony_cistatic int txx9_dc_disable __initdata; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci#if defined(CONFIG_CPU_TX49XX) 1508c2ecf20Sopenharmony_ci/* flush all cache on very early stage (before 4k_cache_init) */ 1518c2ecf20Sopenharmony_cistatic void __init early_flush_dcache(void) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci unsigned int conf = read_c0_config(); 1548c2ecf20Sopenharmony_ci unsigned int dc_size = 1 << (12 + ((conf & CONF_DC) >> 6)); 1558c2ecf20Sopenharmony_ci unsigned int linesz = 32; 1568c2ecf20Sopenharmony_ci unsigned long addr, end; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci end = INDEX_BASE + dc_size / 4; 1598c2ecf20Sopenharmony_ci /* 4way, waybit=0 */ 1608c2ecf20Sopenharmony_ci for (addr = INDEX_BASE; addr < end; addr += linesz) { 1618c2ecf20Sopenharmony_ci cache_op(Index_Writeback_Inv_D, addr | 0); 1628c2ecf20Sopenharmony_ci cache_op(Index_Writeback_Inv_D, addr | 1); 1638c2ecf20Sopenharmony_ci cache_op(Index_Writeback_Inv_D, addr | 2); 1648c2ecf20Sopenharmony_ci cache_op(Index_Writeback_Inv_D, addr | 3); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void __init txx9_cache_fixup(void) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci unsigned int conf; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci conf = read_c0_config(); 1738c2ecf20Sopenharmony_ci /* flush and disable */ 1748c2ecf20Sopenharmony_ci if (txx9_ic_disable) { 1758c2ecf20Sopenharmony_ci conf |= TX49_CONF_IC; 1768c2ecf20Sopenharmony_ci write_c0_config(conf); 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci if (txx9_dc_disable) { 1798c2ecf20Sopenharmony_ci early_flush_dcache(); 1808c2ecf20Sopenharmony_ci conf |= TX49_CONF_DC; 1818c2ecf20Sopenharmony_ci write_c0_config(conf); 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* enable cache */ 1858c2ecf20Sopenharmony_ci conf = read_c0_config(); 1868c2ecf20Sopenharmony_ci if (!txx9_ic_disable) 1878c2ecf20Sopenharmony_ci conf &= ~TX49_CONF_IC; 1888c2ecf20Sopenharmony_ci if (!txx9_dc_disable) 1898c2ecf20Sopenharmony_ci conf &= ~TX49_CONF_DC; 1908c2ecf20Sopenharmony_ci write_c0_config(conf); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (conf & TX49_CONF_IC) 1938c2ecf20Sopenharmony_ci pr_info("TX49XX I-Cache disabled.\n"); 1948c2ecf20Sopenharmony_ci if (conf & TX49_CONF_DC) 1958c2ecf20Sopenharmony_ci pr_info("TX49XX D-Cache disabled.\n"); 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci#elif defined(CONFIG_CPU_TX39XX) 1988c2ecf20Sopenharmony_ci/* flush all cache on very early stage (before tx39_cache_init) */ 1998c2ecf20Sopenharmony_cistatic void __init early_flush_dcache(void) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci unsigned int conf = read_c0_config(); 2028c2ecf20Sopenharmony_ci unsigned int dc_size = 1 << (10 + ((conf & TX39_CONF_DCS_MASK) >> 2038c2ecf20Sopenharmony_ci TX39_CONF_DCS_SHIFT)); 2048c2ecf20Sopenharmony_ci unsigned int linesz = 16; 2058c2ecf20Sopenharmony_ci unsigned long addr, end; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci end = INDEX_BASE + dc_size / 2; 2088c2ecf20Sopenharmony_ci /* 2way, waybit=0 */ 2098c2ecf20Sopenharmony_ci for (addr = INDEX_BASE; addr < end; addr += linesz) { 2108c2ecf20Sopenharmony_ci cache_op(Index_Writeback_Inv_D, addr | 0); 2118c2ecf20Sopenharmony_ci cache_op(Index_Writeback_Inv_D, addr | 1); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic void __init txx9_cache_fixup(void) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci unsigned int conf; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci conf = read_c0_config(); 2208c2ecf20Sopenharmony_ci /* flush and disable */ 2218c2ecf20Sopenharmony_ci if (txx9_ic_disable) { 2228c2ecf20Sopenharmony_ci conf &= ~TX39_CONF_ICE; 2238c2ecf20Sopenharmony_ci write_c0_config(conf); 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci if (txx9_dc_disable) { 2268c2ecf20Sopenharmony_ci early_flush_dcache(); 2278c2ecf20Sopenharmony_ci conf &= ~TX39_CONF_DCE; 2288c2ecf20Sopenharmony_ci write_c0_config(conf); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* enable cache */ 2328c2ecf20Sopenharmony_ci conf = read_c0_config(); 2338c2ecf20Sopenharmony_ci if (!txx9_ic_disable) 2348c2ecf20Sopenharmony_ci conf |= TX39_CONF_ICE; 2358c2ecf20Sopenharmony_ci if (!txx9_dc_disable) 2368c2ecf20Sopenharmony_ci conf |= TX39_CONF_DCE; 2378c2ecf20Sopenharmony_ci write_c0_config(conf); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (!(conf & TX39_CONF_ICE)) 2408c2ecf20Sopenharmony_ci pr_info("TX39XX I-Cache disabled.\n"); 2418c2ecf20Sopenharmony_ci if (!(conf & TX39_CONF_DCE)) 2428c2ecf20Sopenharmony_ci pr_info("TX39XX D-Cache disabled.\n"); 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci#else 2458c2ecf20Sopenharmony_cistatic inline void txx9_cache_fixup(void) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci#endif 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void __init preprocess_cmdline(void) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci static char cmdline[COMMAND_LINE_SIZE] __initdata; 2538c2ecf20Sopenharmony_ci char *s; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci strcpy(cmdline, arcs_cmdline); 2568c2ecf20Sopenharmony_ci s = cmdline; 2578c2ecf20Sopenharmony_ci arcs_cmdline[0] = '\0'; 2588c2ecf20Sopenharmony_ci while (s && *s) { 2598c2ecf20Sopenharmony_ci char *str = strsep(&s, " "); 2608c2ecf20Sopenharmony_ci if (strncmp(str, "board=", 6) == 0) { 2618c2ecf20Sopenharmony_ci txx9_board_vec = find_board_byname(str + 6); 2628c2ecf20Sopenharmony_ci continue; 2638c2ecf20Sopenharmony_ci } else if (strncmp(str, "masterclk=", 10) == 0) { 2648c2ecf20Sopenharmony_ci unsigned int val; 2658c2ecf20Sopenharmony_ci if (kstrtouint(str + 10, 10, &val) == 0) 2668c2ecf20Sopenharmony_ci txx9_master_clock = val; 2678c2ecf20Sopenharmony_ci continue; 2688c2ecf20Sopenharmony_ci } else if (strcmp(str, "icdisable") == 0) { 2698c2ecf20Sopenharmony_ci txx9_ic_disable = 1; 2708c2ecf20Sopenharmony_ci continue; 2718c2ecf20Sopenharmony_ci } else if (strcmp(str, "dcdisable") == 0) { 2728c2ecf20Sopenharmony_ci txx9_dc_disable = 1; 2738c2ecf20Sopenharmony_ci continue; 2748c2ecf20Sopenharmony_ci } else if (strcmp(str, "toeoff") == 0) { 2758c2ecf20Sopenharmony_ci txx9_ccfg_toeon = 0; 2768c2ecf20Sopenharmony_ci continue; 2778c2ecf20Sopenharmony_ci } else if (strcmp(str, "toeon") == 0) { 2788c2ecf20Sopenharmony_ci txx9_ccfg_toeon = 1; 2798c2ecf20Sopenharmony_ci continue; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci if (arcs_cmdline[0]) 2828c2ecf20Sopenharmony_ci strcat(arcs_cmdline, " "); 2838c2ecf20Sopenharmony_ci strcat(arcs_cmdline, str); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci txx9_cache_fixup(); 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void __init select_board(void) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci const char *envstr; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* first, determine by "board=" argument in preprocess_cmdline() */ 2948c2ecf20Sopenharmony_ci if (txx9_board_vec) 2958c2ecf20Sopenharmony_ci return; 2968c2ecf20Sopenharmony_ci /* next, determine by "board" envvar */ 2978c2ecf20Sopenharmony_ci envstr = prom_getenv("board"); 2988c2ecf20Sopenharmony_ci if (envstr) { 2998c2ecf20Sopenharmony_ci txx9_board_vec = find_board_byname(envstr); 3008c2ecf20Sopenharmony_ci if (txx9_board_vec) 3018c2ecf20Sopenharmony_ci return; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci /* select "default" board */ 3058c2ecf20Sopenharmony_ci#ifdef CONFIG_TOSHIBA_JMR3927 3068c2ecf20Sopenharmony_ci txx9_board_vec = &jmr3927_vec; 3078c2ecf20Sopenharmony_ci#endif 3088c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_TX49XX 3098c2ecf20Sopenharmony_ci switch (TX4938_REV_PCODE()) { 3108c2ecf20Sopenharmony_ci#ifdef CONFIG_TOSHIBA_RBTX4927 3118c2ecf20Sopenharmony_ci case 0x4927: 3128c2ecf20Sopenharmony_ci txx9_board_vec = &rbtx4927_vec; 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci case 0x4937: 3158c2ecf20Sopenharmony_ci txx9_board_vec = &rbtx4937_vec; 3168c2ecf20Sopenharmony_ci break; 3178c2ecf20Sopenharmony_ci#endif 3188c2ecf20Sopenharmony_ci#ifdef CONFIG_TOSHIBA_RBTX4938 3198c2ecf20Sopenharmony_ci case 0x4938: 3208c2ecf20Sopenharmony_ci txx9_board_vec = &rbtx4938_vec; 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci#endif 3238c2ecf20Sopenharmony_ci#ifdef CONFIG_TOSHIBA_RBTX4939 3248c2ecf20Sopenharmony_ci case 0x4939: 3258c2ecf20Sopenharmony_ci txx9_board_vec = &rbtx4939_vec; 3268c2ecf20Sopenharmony_ci break; 3278c2ecf20Sopenharmony_ci#endif 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci#endif 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_civoid __init prom_init(void) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci prom_init_cmdline(); 3358c2ecf20Sopenharmony_ci preprocess_cmdline(); 3368c2ecf20Sopenharmony_ci select_board(); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci strcpy(txx9_system_type, txx9_board_vec->system); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci txx9_board_vec->prom_init(); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_civoid __init prom_free_prom_memory(void) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ciconst char *get_system_type(void) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci return txx9_system_type; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ciconst char *__init prom_getenv(const char *name) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci const s32 *str; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (fw_arg2 < CKSEG0) 3578c2ecf20Sopenharmony_ci return NULL; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci str = (const s32 *)fw_arg2; 3608c2ecf20Sopenharmony_ci /* YAMON style ("name", "value" pairs) */ 3618c2ecf20Sopenharmony_ci while (str[0] && str[1]) { 3628c2ecf20Sopenharmony_ci if (!strcmp((const char *)(unsigned long)str[0], name)) 3638c2ecf20Sopenharmony_ci return (const char *)(unsigned long)str[1]; 3648c2ecf20Sopenharmony_ci str += 2; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci return NULL; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic void __noreturn txx9_machine_halt(void) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci local_irq_disable(); 3728c2ecf20Sopenharmony_ci clear_c0_status(ST0_IM); 3738c2ecf20Sopenharmony_ci while (1) { 3748c2ecf20Sopenharmony_ci if (cpu_wait) { 3758c2ecf20Sopenharmony_ci (*cpu_wait)(); 3768c2ecf20Sopenharmony_ci if (cpu_has_counter) { 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * Clear counter interrupt while it 3798c2ecf20Sopenharmony_ci * breaks WAIT instruction even if 3808c2ecf20Sopenharmony_ci * masked. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci write_c0_compare(0); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci/* Watchdog support */ 3898c2ecf20Sopenharmony_civoid __init txx9_wdt_init(unsigned long base) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct resource res = { 3928c2ecf20Sopenharmony_ci .start = base, 3938c2ecf20Sopenharmony_ci .end = base + 0x100 - 1, 3948c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 3958c2ecf20Sopenharmony_ci }; 3968c2ecf20Sopenharmony_ci platform_device_register_simple("txx9wdt", -1, &res, 1); 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_civoid txx9_wdt_now(unsigned long base) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct txx9_tmr_reg __iomem *tmrptr = 4028c2ecf20Sopenharmony_ci ioremap(base, sizeof(struct txx9_tmr_reg)); 4038c2ecf20Sopenharmony_ci /* disable watch dog timer */ 4048c2ecf20Sopenharmony_ci __raw_writel(TXx9_TMWTMR_WDIS | TXx9_TMWTMR_TWC, &tmrptr->wtmr); 4058c2ecf20Sopenharmony_ci __raw_writel(0, &tmrptr->tcr); 4068c2ecf20Sopenharmony_ci /* kick watchdog */ 4078c2ecf20Sopenharmony_ci __raw_writel(TXx9_TMWTMR_TWIE, &tmrptr->wtmr); 4088c2ecf20Sopenharmony_ci __raw_writel(1, &tmrptr->cpra); /* immediate */ 4098c2ecf20Sopenharmony_ci __raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG, 4108c2ecf20Sopenharmony_ci &tmrptr->tcr); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci/* SPI support */ 4148c2ecf20Sopenharmony_civoid __init txx9_spi_init(int busid, unsigned long base, int irq) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci struct resource res[] = { 4178c2ecf20Sopenharmony_ci { 4188c2ecf20Sopenharmony_ci .start = base, 4198c2ecf20Sopenharmony_ci .end = base + 0x20 - 1, 4208c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 4218c2ecf20Sopenharmony_ci }, { 4228c2ecf20Sopenharmony_ci .start = irq, 4238c2ecf20Sopenharmony_ci .flags = IORESOURCE_IRQ, 4248c2ecf20Sopenharmony_ci }, 4258c2ecf20Sopenharmony_ci }; 4268c2ecf20Sopenharmony_ci platform_device_register_simple("spi_txx9", busid, 4278c2ecf20Sopenharmony_ci res, ARRAY_SIZE(res)); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_civoid __init txx9_ethaddr_init(unsigned int id, unsigned char *ethaddr) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct platform_device *pdev = 4338c2ecf20Sopenharmony_ci platform_device_alloc("tc35815-mac", id); 4348c2ecf20Sopenharmony_ci if (!pdev || 4358c2ecf20Sopenharmony_ci platform_device_add_data(pdev, ethaddr, 6) || 4368c2ecf20Sopenharmony_ci platform_device_add(pdev)) 4378c2ecf20Sopenharmony_ci platform_device_put(pdev); 4388c2ecf20Sopenharmony_ci} 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_civoid __init txx9_sio_init(unsigned long baseaddr, int irq, 4418c2ecf20Sopenharmony_ci unsigned int line, unsigned int sclk, int nocts) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_TXX9 4448c2ecf20Sopenharmony_ci struct uart_port req; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci memset(&req, 0, sizeof(req)); 4478c2ecf20Sopenharmony_ci req.line = line; 4488c2ecf20Sopenharmony_ci req.iotype = UPIO_MEM; 4498c2ecf20Sopenharmony_ci req.membase = ioremap(baseaddr, 0x24); 4508c2ecf20Sopenharmony_ci req.mapbase = baseaddr; 4518c2ecf20Sopenharmony_ci req.irq = irq; 4528c2ecf20Sopenharmony_ci if (!nocts) 4538c2ecf20Sopenharmony_ci req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/; 4548c2ecf20Sopenharmony_ci if (sclk) { 4558c2ecf20Sopenharmony_ci req.flags |= UPF_MAGIC_MULTIPLIER /*USE_SCLK*/; 4568c2ecf20Sopenharmony_ci req.uartclk = sclk; 4578c2ecf20Sopenharmony_ci } else 4588c2ecf20Sopenharmony_ci req.uartclk = TXX9_IMCLK; 4598c2ecf20Sopenharmony_ci early_serial_txx9_setup(&req); 4608c2ecf20Sopenharmony_ci#endif /* CONFIG_SERIAL_TXX9 */ 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci#ifdef CONFIG_EARLY_PRINTK 4648c2ecf20Sopenharmony_cistatic void null_prom_putchar(char c) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_civoid (*txx9_prom_putchar)(char c) = null_prom_putchar; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_civoid prom_putchar(char c) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci txx9_prom_putchar(c); 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic void __iomem *early_txx9_sio_port; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic void early_txx9_sio_putchar(char c) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci#define TXX9_SICISR 0x0c 4798c2ecf20Sopenharmony_ci#define TXX9_SITFIFO 0x1c 4808c2ecf20Sopenharmony_ci#define TXX9_SICISR_TXALS 0x00000002 4818c2ecf20Sopenharmony_ci while (!(__raw_readl(early_txx9_sio_port + TXX9_SICISR) & 4828c2ecf20Sopenharmony_ci TXX9_SICISR_TXALS)) 4838c2ecf20Sopenharmony_ci ; 4848c2ecf20Sopenharmony_ci __raw_writel(c, early_txx9_sio_port + TXX9_SITFIFO); 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_civoid __init txx9_sio_putchar_init(unsigned long baseaddr) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci early_txx9_sio_port = ioremap(baseaddr, 0x24); 4908c2ecf20Sopenharmony_ci txx9_prom_putchar = early_txx9_sio_putchar; 4918c2ecf20Sopenharmony_ci} 4928c2ecf20Sopenharmony_ci#endif /* CONFIG_EARLY_PRINTK */ 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/* wrappers */ 4958c2ecf20Sopenharmony_civoid __init plat_mem_setup(void) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci ioport_resource.start = 0; 4988c2ecf20Sopenharmony_ci ioport_resource.end = ~0UL; /* no limit */ 4998c2ecf20Sopenharmony_ci iomem_resource.start = 0; 5008c2ecf20Sopenharmony_ci iomem_resource.end = ~0UL; /* no limit */ 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* fallback restart/halt routines */ 5038c2ecf20Sopenharmony_ci _machine_restart = (void (*)(char *))txx9_machine_halt; 5048c2ecf20Sopenharmony_ci _machine_halt = txx9_machine_halt; 5058c2ecf20Sopenharmony_ci pm_power_off = txx9_machine_halt; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 5088c2ecf20Sopenharmony_ci pcibios_plat_setup = txx9_pcibios_setup; 5098c2ecf20Sopenharmony_ci#endif 5108c2ecf20Sopenharmony_ci txx9_board_vec->mem_setup(); 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_civoid __init arch_init_irq(void) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci txx9_board_vec->irq_setup(); 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_civoid __init plat_time_init(void) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_TX49XX 5218c2ecf20Sopenharmony_ci mips_hpt_frequency = txx9_cpu_clock / 2; 5228c2ecf20Sopenharmony_ci#endif 5238c2ecf20Sopenharmony_ci txx9_board_vec->time_init(); 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic void txx9_clk_init(void) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct clk_hw *hw; 5298c2ecf20Sopenharmony_ci int error; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci hw = clk_hw_register_fixed_rate(NULL, "gbus", NULL, 0, txx9_gbus_clock); 5328c2ecf20Sopenharmony_ci if (IS_ERR(hw)) { 5338c2ecf20Sopenharmony_ci error = PTR_ERR(hw); 5348c2ecf20Sopenharmony_ci goto fail; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci hw = clk_hw_register_fixed_factor(NULL, "imbus", "gbus", 0, 1, 2); 5388c2ecf20Sopenharmony_ci error = clk_hw_register_clkdev(hw, "imbus_clk", NULL); 5398c2ecf20Sopenharmony_ci if (error) 5408c2ecf20Sopenharmony_ci goto fail; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_TX49XX 5438c2ecf20Sopenharmony_ci if (TX4938_REV_PCODE() == 0x4938) { 5448c2ecf20Sopenharmony_ci hw = clk_hw_register_fixed_factor(NULL, "spi", "gbus", 0, 1, 4); 5458c2ecf20Sopenharmony_ci error = clk_hw_register_clkdev(hw, "spi-baseclk", NULL); 5468c2ecf20Sopenharmony_ci if (error) 5478c2ecf20Sopenharmony_ci goto fail; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci#endif 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci return; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cifail: 5548c2ecf20Sopenharmony_ci pr_err("Failed to register clocks: %d\n", error); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic int __init _txx9_arch_init(void) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci txx9_clk_init(); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (txx9_board_vec->arch_init) 5628c2ecf20Sopenharmony_ci txx9_board_vec->arch_init(); 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ciarch_initcall(_txx9_arch_init); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic int __init _txx9_device_init(void) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci if (txx9_board_vec->device_init) 5708c2ecf20Sopenharmony_ci txx9_board_vec->device_init(); 5718c2ecf20Sopenharmony_ci return 0; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_cidevice_initcall(_txx9_device_init); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ciint (*txx9_irq_dispatch)(int pending); 5768c2ecf20Sopenharmony_ciasmlinkage void plat_irq_dispatch(void) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci int pending = read_c0_status() & read_c0_cause() & ST0_IM; 5798c2ecf20Sopenharmony_ci int irq = txx9_irq_dispatch(pending); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (likely(irq >= 0)) 5828c2ecf20Sopenharmony_ci do_IRQ(irq); 5838c2ecf20Sopenharmony_ci else 5848c2ecf20Sopenharmony_ci spurious_interrupt(); 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci/* see include/asm-mips/mach-tx39xx/mangle-port.h, for example. */ 5888c2ecf20Sopenharmony_ci#ifdef NEEDS_TXX9_SWIZZLE_ADDR_B 5898c2ecf20Sopenharmony_cistatic unsigned long __swizzle_addr_none(unsigned long port) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci return port; 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ciunsigned long (*__swizzle_addr_b)(unsigned long port) = __swizzle_addr_none; 5948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__swizzle_addr_b); 5958c2ecf20Sopenharmony_ci#endif 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci#ifdef NEEDS_TXX9_IOSWABW 5988c2ecf20Sopenharmony_cistatic u16 ioswabw_default(volatile u16 *a, u16 x) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci return le16_to_cpu(x); 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_cistatic u16 __mem_ioswabw_default(volatile u16 *a, u16 x) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci return x; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ciu16 (*ioswabw)(volatile u16 *a, u16 x) = ioswabw_default; 6078c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ioswabw); 6088c2ecf20Sopenharmony_ciu16 (*__mem_ioswabw)(volatile u16 *a, u16 x) = __mem_ioswabw_default; 6098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__mem_ioswabw); 6108c2ecf20Sopenharmony_ci#endif 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_civoid __init txx9_physmap_flash_init(int no, unsigned long addr, 6138c2ecf20Sopenharmony_ci unsigned long size, 6148c2ecf20Sopenharmony_ci const struct physmap_flash_data *pdata) 6158c2ecf20Sopenharmony_ci{ 6168c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_MTD_PHYSMAP) 6178c2ecf20Sopenharmony_ci struct resource res = { 6188c2ecf20Sopenharmony_ci .start = addr, 6198c2ecf20Sopenharmony_ci .end = addr + size - 1, 6208c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 6218c2ecf20Sopenharmony_ci }; 6228c2ecf20Sopenharmony_ci struct platform_device *pdev; 6238c2ecf20Sopenharmony_ci static struct mtd_partition parts[2]; 6248c2ecf20Sopenharmony_ci struct physmap_flash_data pdata_part; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* If this area contained boot area, make separate partition */ 6278c2ecf20Sopenharmony_ci if (pdata->nr_parts == 0 && !pdata->parts && 6288c2ecf20Sopenharmony_ci addr < 0x1fc00000 && addr + size > 0x1fc00000 && 6298c2ecf20Sopenharmony_ci !parts[0].name) { 6308c2ecf20Sopenharmony_ci parts[0].name = "boot"; 6318c2ecf20Sopenharmony_ci parts[0].offset = 0x1fc00000 - addr; 6328c2ecf20Sopenharmony_ci parts[0].size = addr + size - 0x1fc00000; 6338c2ecf20Sopenharmony_ci parts[1].name = "user"; 6348c2ecf20Sopenharmony_ci parts[1].offset = 0; 6358c2ecf20Sopenharmony_ci parts[1].size = 0x1fc00000 - addr; 6368c2ecf20Sopenharmony_ci pdata_part = *pdata; 6378c2ecf20Sopenharmony_ci pdata_part.nr_parts = ARRAY_SIZE(parts); 6388c2ecf20Sopenharmony_ci pdata_part.parts = parts; 6398c2ecf20Sopenharmony_ci pdata = &pdata_part; 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci pdev = platform_device_alloc("physmap-flash", no); 6438c2ecf20Sopenharmony_ci if (!pdev || 6448c2ecf20Sopenharmony_ci platform_device_add_resources(pdev, &res, 1) || 6458c2ecf20Sopenharmony_ci platform_device_add_data(pdev, pdata, sizeof(*pdata)) || 6468c2ecf20Sopenharmony_ci platform_device_add(pdev)) 6478c2ecf20Sopenharmony_ci platform_device_put(pdev); 6488c2ecf20Sopenharmony_ci#endif 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_civoid __init txx9_ndfmc_init(unsigned long baseaddr, 6528c2ecf20Sopenharmony_ci const struct txx9ndfmc_platform_data *pdata) 6538c2ecf20Sopenharmony_ci{ 6548c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_MTD_NAND_TXX9NDFMC) 6558c2ecf20Sopenharmony_ci struct resource res = { 6568c2ecf20Sopenharmony_ci .start = baseaddr, 6578c2ecf20Sopenharmony_ci .end = baseaddr + 0x1000 - 1, 6588c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 6598c2ecf20Sopenharmony_ci }; 6608c2ecf20Sopenharmony_ci struct platform_device *pdev = platform_device_alloc("txx9ndfmc", -1); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (!pdev || 6638c2ecf20Sopenharmony_ci platform_device_add_resources(pdev, &res, 1) || 6648c2ecf20Sopenharmony_ci platform_device_add_data(pdev, pdata, sizeof(*pdata)) || 6658c2ecf20Sopenharmony_ci platform_device_add(pdev)) 6668c2ecf20Sopenharmony_ci platform_device_put(pdev); 6678c2ecf20Sopenharmony_ci#endif 6688c2ecf20Sopenharmony_ci} 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_LEDS_GPIO) 6718c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(txx9_iocled_lock); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci#define TXX9_IOCLED_MAXLEDS 8 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_cistruct txx9_iocled_data { 6768c2ecf20Sopenharmony_ci struct gpio_chip chip; 6778c2ecf20Sopenharmony_ci u8 cur_val; 6788c2ecf20Sopenharmony_ci void __iomem *mmioaddr; 6798c2ecf20Sopenharmony_ci struct gpio_led_platform_data pdata; 6808c2ecf20Sopenharmony_ci struct gpio_led leds[TXX9_IOCLED_MAXLEDS]; 6818c2ecf20Sopenharmony_ci char names[TXX9_IOCLED_MAXLEDS][32]; 6828c2ecf20Sopenharmony_ci}; 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci struct txx9_iocled_data *data = gpiochip_get_data(chip); 6878c2ecf20Sopenharmony_ci return !!(data->cur_val & (1 << offset)); 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset, 6918c2ecf20Sopenharmony_ci int value) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci struct txx9_iocled_data *data = gpiochip_get_data(chip); 6948c2ecf20Sopenharmony_ci unsigned long flags; 6958c2ecf20Sopenharmony_ci spin_lock_irqsave(&txx9_iocled_lock, flags); 6968c2ecf20Sopenharmony_ci if (value) 6978c2ecf20Sopenharmony_ci data->cur_val |= 1 << offset; 6988c2ecf20Sopenharmony_ci else 6998c2ecf20Sopenharmony_ci data->cur_val &= ~(1 << offset); 7008c2ecf20Sopenharmony_ci writeb(data->cur_val, data->mmioaddr); 7018c2ecf20Sopenharmony_ci mmiowb(); 7028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&txx9_iocled_lock, flags); 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic int txx9_iocled_dir_in(struct gpio_chip *chip, unsigned int offset) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci return 0; 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic int txx9_iocled_dir_out(struct gpio_chip *chip, unsigned int offset, 7118c2ecf20Sopenharmony_ci int value) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci txx9_iocled_set(chip, offset, value); 7148c2ecf20Sopenharmony_ci return 0; 7158c2ecf20Sopenharmony_ci} 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_civoid __init txx9_iocled_init(unsigned long baseaddr, 7188c2ecf20Sopenharmony_ci int basenum, unsigned int num, int lowactive, 7198c2ecf20Sopenharmony_ci const char *color, char **deftriggers) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci struct txx9_iocled_data *iocled; 7228c2ecf20Sopenharmony_ci struct platform_device *pdev; 7238c2ecf20Sopenharmony_ci int i; 7248c2ecf20Sopenharmony_ci static char *default_triggers[] __initdata = { 7258c2ecf20Sopenharmony_ci "heartbeat", 7268c2ecf20Sopenharmony_ci "disk-activity", 7278c2ecf20Sopenharmony_ci "nand-disk", 7288c2ecf20Sopenharmony_ci NULL, 7298c2ecf20Sopenharmony_ci }; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (!deftriggers) 7328c2ecf20Sopenharmony_ci deftriggers = default_triggers; 7338c2ecf20Sopenharmony_ci iocled = kzalloc(sizeof(*iocled), GFP_KERNEL); 7348c2ecf20Sopenharmony_ci if (!iocled) 7358c2ecf20Sopenharmony_ci return; 7368c2ecf20Sopenharmony_ci iocled->mmioaddr = ioremap(baseaddr, 1); 7378c2ecf20Sopenharmony_ci if (!iocled->mmioaddr) 7388c2ecf20Sopenharmony_ci goto out_free; 7398c2ecf20Sopenharmony_ci iocled->chip.get = txx9_iocled_get; 7408c2ecf20Sopenharmony_ci iocled->chip.set = txx9_iocled_set; 7418c2ecf20Sopenharmony_ci iocled->chip.direction_input = txx9_iocled_dir_in; 7428c2ecf20Sopenharmony_ci iocled->chip.direction_output = txx9_iocled_dir_out; 7438c2ecf20Sopenharmony_ci iocled->chip.label = "iocled"; 7448c2ecf20Sopenharmony_ci iocled->chip.base = basenum; 7458c2ecf20Sopenharmony_ci iocled->chip.ngpio = num; 7468c2ecf20Sopenharmony_ci if (gpiochip_add_data(&iocled->chip, iocled)) 7478c2ecf20Sopenharmony_ci goto out_unmap; 7488c2ecf20Sopenharmony_ci if (basenum < 0) 7498c2ecf20Sopenharmony_ci basenum = iocled->chip.base; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci pdev = platform_device_alloc("leds-gpio", basenum); 7528c2ecf20Sopenharmony_ci if (!pdev) 7538c2ecf20Sopenharmony_ci goto out_gpio; 7548c2ecf20Sopenharmony_ci iocled->pdata.num_leds = num; 7558c2ecf20Sopenharmony_ci iocled->pdata.leds = iocled->leds; 7568c2ecf20Sopenharmony_ci for (i = 0; i < num; i++) { 7578c2ecf20Sopenharmony_ci struct gpio_led *led = &iocled->leds[i]; 7588c2ecf20Sopenharmony_ci snprintf(iocled->names[i], sizeof(iocled->names[i]), 7598c2ecf20Sopenharmony_ci "iocled:%s:%u", color, i); 7608c2ecf20Sopenharmony_ci led->name = iocled->names[i]; 7618c2ecf20Sopenharmony_ci led->gpio = basenum + i; 7628c2ecf20Sopenharmony_ci led->active_low = lowactive; 7638c2ecf20Sopenharmony_ci if (deftriggers && *deftriggers) 7648c2ecf20Sopenharmony_ci led->default_trigger = *deftriggers++; 7658c2ecf20Sopenharmony_ci } 7668c2ecf20Sopenharmony_ci pdev->dev.platform_data = &iocled->pdata; 7678c2ecf20Sopenharmony_ci if (platform_device_add(pdev)) 7688c2ecf20Sopenharmony_ci goto out_pdev; 7698c2ecf20Sopenharmony_ci return; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ciout_pdev: 7728c2ecf20Sopenharmony_ci platform_device_put(pdev); 7738c2ecf20Sopenharmony_ciout_gpio: 7748c2ecf20Sopenharmony_ci gpiochip_remove(&iocled->chip); 7758c2ecf20Sopenharmony_ciout_unmap: 7768c2ecf20Sopenharmony_ci iounmap(iocled->mmioaddr); 7778c2ecf20Sopenharmony_ciout_free: 7788c2ecf20Sopenharmony_ci kfree(iocled); 7798c2ecf20Sopenharmony_ci} 7808c2ecf20Sopenharmony_ci#else /* CONFIG_LEDS_GPIO */ 7818c2ecf20Sopenharmony_civoid __init txx9_iocled_init(unsigned long baseaddr, 7828c2ecf20Sopenharmony_ci int basenum, unsigned int num, int lowactive, 7838c2ecf20Sopenharmony_ci const char *color, char **deftriggers) 7848c2ecf20Sopenharmony_ci{ 7858c2ecf20Sopenharmony_ci} 7868c2ecf20Sopenharmony_ci#endif /* CONFIG_LEDS_GPIO */ 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_civoid __init txx9_dmac_init(int id, unsigned long baseaddr, int irq, 7898c2ecf20Sopenharmony_ci const struct txx9dmac_platform_data *pdata) 7908c2ecf20Sopenharmony_ci{ 7918c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_TXX9_DMAC) 7928c2ecf20Sopenharmony_ci struct resource res[] = { 7938c2ecf20Sopenharmony_ci { 7948c2ecf20Sopenharmony_ci .start = baseaddr, 7958c2ecf20Sopenharmony_ci .end = baseaddr + 0x800 - 1, 7968c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 7978c2ecf20Sopenharmony_ci#ifndef CONFIG_MACH_TX49XX 7988c2ecf20Sopenharmony_ci }, { 7998c2ecf20Sopenharmony_ci .start = irq, 8008c2ecf20Sopenharmony_ci .flags = IORESOURCE_IRQ, 8018c2ecf20Sopenharmony_ci#endif 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci }; 8048c2ecf20Sopenharmony_ci#ifdef CONFIG_MACH_TX49XX 8058c2ecf20Sopenharmony_ci struct resource chan_res[] = { 8068c2ecf20Sopenharmony_ci { 8078c2ecf20Sopenharmony_ci .flags = IORESOURCE_IRQ, 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci }; 8108c2ecf20Sopenharmony_ci#endif 8118c2ecf20Sopenharmony_ci struct platform_device *pdev = platform_device_alloc("txx9dmac", id); 8128c2ecf20Sopenharmony_ci struct txx9dmac_chan_platform_data cpdata; 8138c2ecf20Sopenharmony_ci int i; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (!pdev || 8168c2ecf20Sopenharmony_ci platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) || 8178c2ecf20Sopenharmony_ci platform_device_add_data(pdev, pdata, sizeof(*pdata)) || 8188c2ecf20Sopenharmony_ci platform_device_add(pdev)) { 8198c2ecf20Sopenharmony_ci platform_device_put(pdev); 8208c2ecf20Sopenharmony_ci return; 8218c2ecf20Sopenharmony_ci } 8228c2ecf20Sopenharmony_ci memset(&cpdata, 0, sizeof(cpdata)); 8238c2ecf20Sopenharmony_ci cpdata.dmac_dev = pdev; 8248c2ecf20Sopenharmony_ci for (i = 0; i < TXX9_DMA_MAX_NR_CHANNELS; i++) { 8258c2ecf20Sopenharmony_ci#ifdef CONFIG_MACH_TX49XX 8268c2ecf20Sopenharmony_ci chan_res[0].start = irq + i; 8278c2ecf20Sopenharmony_ci#endif 8288c2ecf20Sopenharmony_ci pdev = platform_device_alloc("txx9dmac-chan", 8298c2ecf20Sopenharmony_ci id * TXX9_DMA_MAX_NR_CHANNELS + i); 8308c2ecf20Sopenharmony_ci if (!pdev || 8318c2ecf20Sopenharmony_ci#ifdef CONFIG_MACH_TX49XX 8328c2ecf20Sopenharmony_ci platform_device_add_resources(pdev, chan_res, 8338c2ecf20Sopenharmony_ci ARRAY_SIZE(chan_res)) || 8348c2ecf20Sopenharmony_ci#endif 8358c2ecf20Sopenharmony_ci platform_device_add_data(pdev, &cpdata, sizeof(cpdata)) || 8368c2ecf20Sopenharmony_ci platform_device_add(pdev)) 8378c2ecf20Sopenharmony_ci platform_device_put(pdev); 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci#endif 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_civoid __init txx9_aclc_init(unsigned long baseaddr, int irq, 8438c2ecf20Sopenharmony_ci unsigned int dmac_id, 8448c2ecf20Sopenharmony_ci unsigned int dma_chan_out, 8458c2ecf20Sopenharmony_ci unsigned int dma_chan_in) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_TXX9ACLC) 8488c2ecf20Sopenharmony_ci unsigned int dma_base = dmac_id * TXX9_DMA_MAX_NR_CHANNELS; 8498c2ecf20Sopenharmony_ci struct resource res[] = { 8508c2ecf20Sopenharmony_ci { 8518c2ecf20Sopenharmony_ci .start = baseaddr, 8528c2ecf20Sopenharmony_ci .end = baseaddr + 0x100 - 1, 8538c2ecf20Sopenharmony_ci .flags = IORESOURCE_MEM, 8548c2ecf20Sopenharmony_ci }, { 8558c2ecf20Sopenharmony_ci .start = irq, 8568c2ecf20Sopenharmony_ci .flags = IORESOURCE_IRQ, 8578c2ecf20Sopenharmony_ci }, { 8588c2ecf20Sopenharmony_ci .name = "txx9dmac-chan", 8598c2ecf20Sopenharmony_ci .start = dma_base + dma_chan_out, 8608c2ecf20Sopenharmony_ci .flags = IORESOURCE_DMA, 8618c2ecf20Sopenharmony_ci }, { 8628c2ecf20Sopenharmony_ci .name = "txx9dmac-chan", 8638c2ecf20Sopenharmony_ci .start = dma_base + dma_chan_in, 8648c2ecf20Sopenharmony_ci .flags = IORESOURCE_DMA, 8658c2ecf20Sopenharmony_ci } 8668c2ecf20Sopenharmony_ci }; 8678c2ecf20Sopenharmony_ci struct platform_device *pdev = 8688c2ecf20Sopenharmony_ci platform_device_alloc("txx9aclc-ac97", -1); 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci if (!pdev || 8718c2ecf20Sopenharmony_ci platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) || 8728c2ecf20Sopenharmony_ci platform_device_add(pdev)) 8738c2ecf20Sopenharmony_ci platform_device_put(pdev); 8748c2ecf20Sopenharmony_ci#endif 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic struct bus_type txx9_sramc_subsys = { 8788c2ecf20Sopenharmony_ci .name = "txx9_sram", 8798c2ecf20Sopenharmony_ci .dev_name = "txx9_sram", 8808c2ecf20Sopenharmony_ci}; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistruct txx9_sramc_dev { 8838c2ecf20Sopenharmony_ci struct device dev; 8848c2ecf20Sopenharmony_ci struct bin_attribute bindata_attr; 8858c2ecf20Sopenharmony_ci void __iomem *base; 8868c2ecf20Sopenharmony_ci}; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_cistatic ssize_t txx9_sram_read(struct file *filp, struct kobject *kobj, 8898c2ecf20Sopenharmony_ci struct bin_attribute *bin_attr, 8908c2ecf20Sopenharmony_ci char *buf, loff_t pos, size_t size) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci struct txx9_sramc_dev *dev = bin_attr->private; 8938c2ecf20Sopenharmony_ci size_t ramsize = bin_attr->size; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci if (pos >= ramsize) 8968c2ecf20Sopenharmony_ci return 0; 8978c2ecf20Sopenharmony_ci if (pos + size > ramsize) 8988c2ecf20Sopenharmony_ci size = ramsize - pos; 8998c2ecf20Sopenharmony_ci memcpy_fromio(buf, dev->base + pos, size); 9008c2ecf20Sopenharmony_ci return size; 9018c2ecf20Sopenharmony_ci} 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_cistatic ssize_t txx9_sram_write(struct file *filp, struct kobject *kobj, 9048c2ecf20Sopenharmony_ci struct bin_attribute *bin_attr, 9058c2ecf20Sopenharmony_ci char *buf, loff_t pos, size_t size) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci struct txx9_sramc_dev *dev = bin_attr->private; 9088c2ecf20Sopenharmony_ci size_t ramsize = bin_attr->size; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci if (pos >= ramsize) 9118c2ecf20Sopenharmony_ci return 0; 9128c2ecf20Sopenharmony_ci if (pos + size > ramsize) 9138c2ecf20Sopenharmony_ci size = ramsize - pos; 9148c2ecf20Sopenharmony_ci memcpy_toio(dev->base + pos, buf, size); 9158c2ecf20Sopenharmony_ci return size; 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic void txx9_device_release(struct device *dev) 9198c2ecf20Sopenharmony_ci{ 9208c2ecf20Sopenharmony_ci struct txx9_sramc_dev *tdev; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci tdev = container_of(dev, struct txx9_sramc_dev, dev); 9238c2ecf20Sopenharmony_ci kfree(tdev); 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_civoid __init txx9_sramc_init(struct resource *r) 9278c2ecf20Sopenharmony_ci{ 9288c2ecf20Sopenharmony_ci struct txx9_sramc_dev *dev; 9298c2ecf20Sopenharmony_ci size_t size; 9308c2ecf20Sopenharmony_ci int err; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci err = subsys_system_register(&txx9_sramc_subsys, NULL); 9338c2ecf20Sopenharmony_ci if (err) 9348c2ecf20Sopenharmony_ci return; 9358c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(*dev), GFP_KERNEL); 9368c2ecf20Sopenharmony_ci if (!dev) 9378c2ecf20Sopenharmony_ci return; 9388c2ecf20Sopenharmony_ci size = resource_size(r); 9398c2ecf20Sopenharmony_ci dev->base = ioremap(r->start, size); 9408c2ecf20Sopenharmony_ci if (!dev->base) { 9418c2ecf20Sopenharmony_ci kfree(dev); 9428c2ecf20Sopenharmony_ci return; 9438c2ecf20Sopenharmony_ci } 9448c2ecf20Sopenharmony_ci dev->dev.release = &txx9_device_release; 9458c2ecf20Sopenharmony_ci dev->dev.bus = &txx9_sramc_subsys; 9468c2ecf20Sopenharmony_ci sysfs_bin_attr_init(&dev->bindata_attr); 9478c2ecf20Sopenharmony_ci dev->bindata_attr.attr.name = "bindata"; 9488c2ecf20Sopenharmony_ci dev->bindata_attr.attr.mode = S_IRUSR | S_IWUSR; 9498c2ecf20Sopenharmony_ci dev->bindata_attr.read = txx9_sram_read; 9508c2ecf20Sopenharmony_ci dev->bindata_attr.write = txx9_sram_write; 9518c2ecf20Sopenharmony_ci dev->bindata_attr.size = size; 9528c2ecf20Sopenharmony_ci dev->bindata_attr.private = dev; 9538c2ecf20Sopenharmony_ci err = device_register(&dev->dev); 9548c2ecf20Sopenharmony_ci if (err) 9558c2ecf20Sopenharmony_ci goto exit_put; 9568c2ecf20Sopenharmony_ci err = sysfs_create_bin_file(&dev->dev.kobj, &dev->bindata_attr); 9578c2ecf20Sopenharmony_ci if (err) { 9588c2ecf20Sopenharmony_ci iounmap(dev->base); 9598c2ecf20Sopenharmony_ci device_unregister(&dev->dev); 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci return; 9628c2ecf20Sopenharmony_ciexit_put: 9638c2ecf20Sopenharmony_ci iounmap(dev->base); 9648c2ecf20Sopenharmony_ci put_device(&dev->dev); 9658c2ecf20Sopenharmony_ci} 966