1
0
Fork 0
alistair23-linux/arch/mips/txx9/generic/setup.c

966 lines
22 KiB
C
Raw Normal View History

/*
* Based on linux/arch/mips/txx9/rbtx4938/setup.c,
* and RBTX49xx patch from CELF patch archive.
*
* 2003-2005 (c) MontaVista Software, Inc.
* (C) Copyright TOSHIBA CORPORATION 2000-2001, 2004-2007
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/string.h>
MIPS: Audit and remove any unnecessary uses of module.h Historically a lot of these existed because we did not have a distinction between what was modular code and what was providing support to modules via EXPORT_SYMBOL and friends. That changed when we forked out support for the latter into the export.h file. This means we should be able to reduce the usage of module.h in code that is obj-y Makefile or bool Kconfig. In the case of some code where it is modular, we can extend that to also include files that are building basic support functionality but not related to loading or registering the final module; such files also have no need whatsoever for module.h The advantage in removing such instances is that module.h itself sources about 15 other headers; adding significantly to what we feed cpp, and it can obscure what headers we are effectively using. Since module.h might have been the implicit source for init.h (for __init) and for export.h (for EXPORT_SYMBOL) we consider each instance for the presence of either and replace/add as needed. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. Build coverage of all the mips defconfigs revealed the module.h header was masking a couple of implicit include instances, so we add the appropriate headers there. Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> Cc: David Daney <david.daney@cavium.com> Cc: John Crispin <john@phrozen.org> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: "Steven J. Hill" <steven.hill@cavium.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/15131/ [james.hogan@imgtec.com: Preserve sort order where it already exists] Signed-off-by: James Hogan <james.hogan@imgtec.com>
2017-01-28 19:05:57 -07:00
#include <linux/export.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/platform_device.h>
#include <linux/platform_data/txx9/ndfmc.h>
#include <linux/serial_core.h>
#include <linux/mtd/physmap.h>
#include <linux/leds.h>
#include <linux/device.h>
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo <tj@kernel.org> Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 02:04:11 -06:00
#include <linux/slab.h>
clk: Remove io.h from clk-provider.h Now that we've gotten rid of clk_readl() we can remove io.h from the clk-provider header and push out the io.h include to any code that isn't already including the io.h header but using things like readl/writel, etc. Found with this grep: git grep -l clk-provider.h | grep '.c$' | xargs git grep -L 'linux/io.h' | \ xargs git grep -l \ -e '\<__iowrite32_copy\>' --or \ -e '\<__ioread32_copy\>' --or \ -e '\<__iowrite64_copy\>' --or \ -e '\<ioremap_page_range\>' --or \ -e '\<ioremap_huge_init\>' --or \ -e '\<arch_ioremap_pud_supported\>' --or \ -e '\<arch_ioremap_pmd_supported\>' --or \ -e '\<devm_ioport_map\>' --or \ -e '\<devm_ioport_unmap\>' --or \ -e '\<IOMEM_ERR_PTR\>' --or \ -e '\<devm_ioremap\>' --or \ -e '\<devm_ioremap_nocache\>' --or \ -e '\<devm_ioremap_wc\>' --or \ -e '\<devm_iounmap\>' --or \ -e '\<devm_ioremap_release\>' --or \ -e '\<devm_memremap\>' --or \ -e '\<devm_memunmap\>' --or \ -e '\<__devm_memremap_pages\>' --or \ -e '\<pci_remap_cfgspace\>' --or \ -e '\<arch_has_dev_port\>' --or \ -e '\<arch_phys_wc_add\>' --or \ -e '\<arch_phys_wc_del\>' --or \ -e '\<memremap\>' --or \ -e '\<memunmap\>' --or \ -e '\<arch_io_reserve_memtype_wc\>' --or \ -e '\<arch_io_free_memtype_wc\>' --or \ -e '\<__io_aw\>' --or \ -e '\<__io_pbw\>' --or \ -e '\<__io_paw\>' --or \ -e '\<__io_pbr\>' --or \ -e '\<__io_par\>' --or \ -e '\<__raw_readb\>' --or \ -e '\<__raw_readw\>' --or \ -e '\<__raw_readl\>' --or \ -e '\<__raw_readq\>' --or \ -e '\<__raw_writeb\>' --or \ -e '\<__raw_writew\>' --or \ -e '\<__raw_writel\>' --or \ -e '\<__raw_writeq\>' --or \ -e '\<readb\>' --or \ -e '\<readw\>' --or \ -e '\<readl\>' --or \ -e '\<readq\>' --or \ -e '\<writeb\>' --or \ -e '\<writew\>' --or \ -e '\<writel\>' --or \ -e '\<writeq\>' --or \ -e '\<readb_relaxed\>' --or \ -e '\<readw_relaxed\>' --or \ -e '\<readl_relaxed\>' --or \ -e '\<readq_relaxed\>' --or \ -e '\<writeb_relaxed\>' --or \ -e '\<writew_relaxed\>' --or \ -e '\<writel_relaxed\>' --or \ -e '\<writeq_relaxed\>' --or \ -e '\<readsb\>' --or \ -e '\<readsw\>' --or \ -e '\<readsl\>' --or \ -e '\<readsq\>' --or \ -e '\<writesb\>' --or \ -e '\<writesw\>' --or \ -e '\<writesl\>' --or \ -e '\<writesq\>' --or \ -e '\<inb\>' --or \ -e '\<inw\>' --or \ -e '\<inl\>' --or \ -e '\<outb\>' --or \ -e '\<outw\>' --or \ -e '\<outl\>' --or \ -e '\<inb_p\>' --or \ -e '\<inw_p\>' --or \ -e '\<inl_p\>' --or \ -e '\<outb_p\>' --or \ -e '\<outw_p\>' --or \ -e '\<outl_p\>' --or \ -e '\<insb\>' --or \ -e '\<insw\>' --or \ -e '\<insl\>' --or \ -e '\<outsb\>' --or \ -e '\<outsw\>' --or \ -e '\<outsl\>' --or \ -e '\<insb_p\>' --or \ -e '\<insw_p\>' --or \ -e '\<insl_p\>' --or \ -e '\<outsb_p\>' --or \ -e '\<outsw_p\>' --or \ -e '\<outsl_p\>' --or \ -e '\<ioread8\>' --or \ -e '\<ioread16\>' --or \ -e '\<ioread32\>' --or \ -e '\<ioread64\>' --or \ -e '\<iowrite8\>' --or \ -e '\<iowrite16\>' --or \ -e '\<iowrite32\>' --or \ -e '\<iowrite64\>' --or \ -e '\<ioread16be\>' --or \ -e '\<ioread32be\>' --or \ -e '\<ioread64be\>' --or \ -e '\<iowrite16be\>' --or \ -e '\<iowrite32be\>' --or \ -e '\<iowrite64be\>' --or \ -e '\<ioread8_rep\>' --or \ -e '\<ioread16_rep\>' --or \ -e '\<ioread32_rep\>' --or \ -e '\<ioread64_rep\>' --or \ -e '\<iowrite8_rep\>' --or \ -e '\<iowrite16_rep\>' --or \ -e '\<iowrite32_rep\>' --or \ -e '\<iowrite64_rep\>' --or \ -e '\<__io_virt\>' --or \ -e '\<pci_iounmap\>' --or \ -e '\<virt_to_phys\>' --or \ -e '\<phys_to_virt\>' --or \ -e '\<ioremap_uc\>' --or \ -e '\<ioremap\>' --or \ -e '\<__ioremap\>' --or \ -e '\<iounmap\>' --or \ -e '\<ioremap\>' --or \ -e '\<ioremap_nocache\>' --or \ -e '\<ioremap_uc\>' --or \ -e '\<ioremap_wc\>' --or \ -e '\<ioremap_wc\>' --or \ -e '\<ioremap_wt\>' --or \ -e '\<ioport_map\>' --or \ -e '\<ioport_unmap\>' --or \ -e '\<ioport_map\>' --or \ -e '\<ioport_unmap\>' --or \ -e '\<xlate_dev_kmem_ptr\>' --or \ -e '\<xlate_dev_mem_ptr\>' --or \ -e '\<unxlate_dev_mem_ptr\>' --or \ -e '\<virt_to_bus\>' --or \ -e '\<bus_to_virt\>' --or \ -e '\<memset_io\>' --or \ -e '\<memcpy_fromio\>' --or \ -e '\<memcpy_toio\>' I also reordered a couple includes when they weren't alphabetical and removed clk.h from kona, replacing it with clk-provider.h because that driver doesn't use clk consumer APIs. Acked-by: Geert Uytterhoeven <geert+renesas@glider.be> Cc: Chen-Yu Tsai <wens@csie.org> Acked-by: Maxime Ripard <maxime.ripard@bootlin.com> Acked-by: Tero Kristo <t-kristo@ti.com> Acked-by: Sekhar Nori <nsekhar@ti.com> Cc: Krzysztof Kozlowski <krzk@kernel.org> Acked-by: Mark Brown <broonie@kernel.org> Cc: Chris Zankel <chris@zankel.net> Acked-by: Max Filippov <jcmvbkbc@gmail.com> Acked-by: John Crispin <john@phrozen.org> Acked-by: Heiko Stuebner <heiko@sntech.de> Signed-off-by: Stephen Boyd <sboyd@kernel.org>
2019-04-18 16:20:22 -06:00
#include <linux/io.h>
#include <linux/irq.h>
#include <asm/bootinfo.h>
#include <asm/idle.h>
#include <asm/time.h>
#include <asm/reboot.h>
#include <asm/r4kcache.h>
#include <asm/setup.h>
#include <asm/txx9/generic.h>
#include <asm/txx9/pci.h>
#include <asm/txx9tmr.h>
#include <asm/txx9/dmac.h>
#ifdef CONFIG_CPU_TX49XX
#include <asm/txx9/tx4938.h>
#endif
/* EBUSC settings of TX4927, etc. */
struct resource txx9_ce_res[8];
static char txx9_ce_res_name[8][4]; /* "CEn" */
/* pcode, internal register */
unsigned int txx9_pcode;
char txx9_pcode_str[8];
static struct resource txx9_reg_res = {
.name = txx9_pcode_str,
.flags = IORESOURCE_MEM,
};
void __init
txx9_reg_res_init(unsigned int pcode, unsigned long base, unsigned long size)
{
int i;
for (i = 0; i < ARRAY_SIZE(txx9_ce_res); i++) {
sprintf(txx9_ce_res_name[i], "CE%d", i);
txx9_ce_res[i].flags = IORESOURCE_MEM;
txx9_ce_res[i].name = txx9_ce_res_name[i];
}
txx9_pcode = pcode;
sprintf(txx9_pcode_str, "TX%x", pcode);
if (base) {
txx9_reg_res.start = base & 0xfffffffffULL;
txx9_reg_res.end = (base & 0xfffffffffULL) + (size - 1);
request_resource(&iomem_resource, &txx9_reg_res);
}
}
/* clocks */
unsigned int txx9_master_clock;
unsigned int txx9_cpu_clock;
unsigned int txx9_gbus_clock;
#ifdef CONFIG_CPU_TX39XX
/* don't enable by default - see errata */
int txx9_ccfg_toeon __initdata;
#else
int txx9_ccfg_toeon __initdata = 1;
#endif
#define BOARD_VEC(board) extern struct txx9_board_vec board;
#include <asm/txx9/boards.h>
#undef BOARD_VEC
struct txx9_board_vec *txx9_board_vec __initdata;
static char txx9_system_type[32];
static struct txx9_board_vec *board_vecs[] __initdata = {
#define BOARD_VEC(board) &board,
#include <asm/txx9/boards.h>
#undef BOARD_VEC
};
static struct txx9_board_vec *__init find_board_byname(const char *name)
{
int i;
/* search board_vecs table */
for (i = 0; i < ARRAY_SIZE(board_vecs); i++) {
if (strstr(board_vecs[i]->system, name))
return board_vecs[i];
}
return NULL;
}
static void __init prom_init_cmdline(void)
{
int argc;
int *argv32;
int i; /* Always ignore the "-c" at argv[0] */
if (fw_arg0 >= CKSEG0 || fw_arg1 < CKSEG0) {
/*
* argc is not a valid number, or argv32 is not a valid
* pointer
*/
argc = 0;
argv32 = NULL;
} else {
argc = (int)fw_arg0;
argv32 = (int *)fw_arg1;
}
arcs_cmdline[0] = '\0';
for (i = 1; i < argc; i++) {
char *str = (char *)(long)argv32[i];
if (i != 1)
strcat(arcs_cmdline, " ");
if (strchr(str, ' ')) {
strcat(arcs_cmdline, "\"");
strcat(arcs_cmdline, str);
strcat(arcs_cmdline, "\"");
} else
strcat(arcs_cmdline, str);
}
}
static int txx9_ic_disable __initdata;
static int txx9_dc_disable __initdata;
#if defined(CONFIG_CPU_TX49XX)
/* flush all cache on very early stage (before 4k_cache_init) */
static void __init early_flush_dcache(void)
{
unsigned int conf = read_c0_config();
unsigned int dc_size = 1 << (12 + ((conf & CONF_DC) >> 6));
unsigned int linesz = 32;
unsigned long addr, end;
end = INDEX_BASE + dc_size / 4;
/* 4way, waybit=0 */
for (addr = INDEX_BASE; addr < end; addr += linesz) {
cache_op(Index_Writeback_Inv_D, addr | 0);
cache_op(Index_Writeback_Inv_D, addr | 1);
cache_op(Index_Writeback_Inv_D, addr | 2);
cache_op(Index_Writeback_Inv_D, addr | 3);
}
}
static void __init txx9_cache_fixup(void)
{
unsigned int conf;
conf = read_c0_config();
/* flush and disable */
if (txx9_ic_disable) {
conf |= TX49_CONF_IC;
write_c0_config(conf);
}
if (txx9_dc_disable) {
early_flush_dcache();
conf |= TX49_CONF_DC;
write_c0_config(conf);
}
/* enable cache */
conf = read_c0_config();
if (!txx9_ic_disable)
conf &= ~TX49_CONF_IC;
if (!txx9_dc_disable)
conf &= ~TX49_CONF_DC;
write_c0_config(conf);
if (conf & TX49_CONF_IC)
pr_info("TX49XX I-Cache disabled.\n");
if (conf & TX49_CONF_DC)
pr_info("TX49XX D-Cache disabled.\n");
}
#elif defined(CONFIG_CPU_TX39XX)
/* flush all cache on very early stage (before tx39_cache_init) */
static void __init early_flush_dcache(void)
{
unsigned int conf = read_c0_config();
unsigned int dc_size = 1 << (10 + ((conf & TX39_CONF_DCS_MASK) >>
TX39_CONF_DCS_SHIFT));
unsigned int linesz = 16;
unsigned long addr, end;
end = INDEX_BASE + dc_size / 2;
/* 2way, waybit=0 */
for (addr = INDEX_BASE; addr < end; addr += linesz) {
cache_op(Index_Writeback_Inv_D, addr | 0);
cache_op(Index_Writeback_Inv_D, addr | 1);
}
}
static void __init txx9_cache_fixup(void)
{
unsigned int conf;
conf = read_c0_config();
/* flush and disable */
if (txx9_ic_disable) {
conf &= ~TX39_CONF_ICE;
write_c0_config(conf);
}
if (txx9_dc_disable) {
early_flush_dcache();
conf &= ~TX39_CONF_DCE;
write_c0_config(conf);
}
/* enable cache */
conf = read_c0_config();
if (!txx9_ic_disable)
conf |= TX39_CONF_ICE;
if (!txx9_dc_disable)
conf |= TX39_CONF_DCE;
write_c0_config(conf);
if (!(conf & TX39_CONF_ICE))
pr_info("TX39XX I-Cache disabled.\n");
if (!(conf & TX39_CONF_DCE))
pr_info("TX39XX D-Cache disabled.\n");
}
#else
static inline void txx9_cache_fixup(void)
{
}
#endif
static void __init preprocess_cmdline(void)
{
static char cmdline[COMMAND_LINE_SIZE] __initdata;
char *s;
strcpy(cmdline, arcs_cmdline);
s = cmdline;
arcs_cmdline[0] = '\0';
while (s && *s) {
char *str = strsep(&s, " ");
if (strncmp(str, "board=", 6) == 0) {
txx9_board_vec = find_board_byname(str + 6);
continue;
} else if (strncmp(str, "masterclk=", 10) == 0) {
unsigned int val;
if (kstrtouint(str + 10, 10, &val) == 0)
txx9_master_clock = val;
continue;
} else if (strcmp(str, "icdisable") == 0) {
txx9_ic_disable = 1;
continue;
} else if (strcmp(str, "dcdisable") == 0) {
txx9_dc_disable = 1;
continue;
} else if (strcmp(str, "toeoff") == 0) {
txx9_ccfg_toeon = 0;
continue;
} else if (strcmp(str, "toeon") == 0) {
txx9_ccfg_toeon = 1;
continue;
}
if (arcs_cmdline[0])
strcat(arcs_cmdline, " ");
strcat(arcs_cmdline, str);
}
txx9_cache_fixup();
}
static void __init select_board(void)
{
const char *envstr;
/* first, determine by "board=" argument in preprocess_cmdline() */
if (txx9_board_vec)
return;
/* next, determine by "board" envvar */
envstr = prom_getenv("board");
if (envstr) {
txx9_board_vec = find_board_byname(envstr);
if (txx9_board_vec)
return;
}
/* select "default" board */
#ifdef CONFIG_TOSHIBA_JMR3927
txx9_board_vec = &jmr3927_vec;
#endif
#ifdef CONFIG_CPU_TX49XX
switch (TX4938_REV_PCODE()) {
#ifdef CONFIG_TOSHIBA_RBTX4927
case 0x4927:
txx9_board_vec = &rbtx4927_vec;
break;
case 0x4937:
txx9_board_vec = &rbtx4937_vec;
break;
#endif
#ifdef CONFIG_TOSHIBA_RBTX4938
case 0x4938:
txx9_board_vec = &rbtx4938_vec;
break;
#endif
#ifdef CONFIG_TOSHIBA_RBTX4939
case 0x4939:
txx9_board_vec = &rbtx4939_vec;
break;
#endif
}
#endif
}
void __init prom_init(void)
{
prom_init_cmdline();
preprocess_cmdline();
select_board();
strcpy(txx9_system_type, txx9_board_vec->system);
txx9_board_vec->prom_init();
}
void __init prom_free_prom_memory(void)
{
}
const char *get_system_type(void)
{
return txx9_system_type;
}
const char *__init prom_getenv(const char *name)
{
const s32 *str;
if (fw_arg2 < CKSEG0)
return NULL;
str = (const s32 *)fw_arg2;
/* YAMON style ("name", "value" pairs) */
while (str[0] && str[1]) {
if (!strcmp((const char *)(unsigned long)str[0], name))
return (const char *)(unsigned long)str[1];
str += 2;
}
return NULL;
}
static void __noreturn txx9_machine_halt(void)
{
local_irq_disable();
clear_c0_status(ST0_IM);
while (1) {
if (cpu_wait) {
(*cpu_wait)();
if (cpu_has_counter) {
/*
* Clear counter interrupt while it
* breaks WAIT instruction even if
* masked.
*/
write_c0_compare(0);
}
}
}
}
/* Watchdog support */
void __init txx9_wdt_init(unsigned long base)
{
struct resource res = {
.start = base,
.end = base + 0x100 - 1,
.flags = IORESOURCE_MEM,
};
platform_device_register_simple("txx9wdt", -1, &res, 1);
}
void txx9_wdt_now(unsigned long base)
{
struct txx9_tmr_reg __iomem *tmrptr =
ioremap(base, sizeof(struct txx9_tmr_reg));
/* disable watch dog timer */
__raw_writel(TXx9_TMWTMR_WDIS | TXx9_TMWTMR_TWC, &tmrptr->wtmr);
__raw_writel(0, &tmrptr->tcr);
/* kick watchdog */
__raw_writel(TXx9_TMWTMR_TWIE, &tmrptr->wtmr);
__raw_writel(1, &tmrptr->cpra); /* immediate */
__raw_writel(TXx9_TMTCR_TCE | TXx9_TMTCR_CCDE | TXx9_TMTCR_TMODE_WDOG,
&tmrptr->tcr);
}
/* SPI support */
void __init txx9_spi_init(int busid, unsigned long base, int irq)
{
struct resource res[] = {
{
.start = base,
.end = base + 0x20 - 1,
.flags = IORESOURCE_MEM,
}, {
.start = irq,
.flags = IORESOURCE_IRQ,
},
};
platform_device_register_simple("spi_txx9", busid,
res, ARRAY_SIZE(res));
}
void __init txx9_ethaddr_init(unsigned int id, unsigned char *ethaddr)
{
struct platform_device *pdev =
platform_device_alloc("tc35815-mac", id);
if (!pdev ||
platform_device_add_data(pdev, ethaddr, 6) ||
platform_device_add(pdev))
platform_device_put(pdev);
}
void __init txx9_sio_init(unsigned long baseaddr, int irq,
unsigned int line, unsigned int sclk, int nocts)
{
#ifdef CONFIG_SERIAL_TXX9
struct uart_port req;
memset(&req, 0, sizeof(req));
req.line = line;
req.iotype = UPIO_MEM;
req.membase = ioremap(baseaddr, 0x24);
req.mapbase = baseaddr;
req.irq = irq;
if (!nocts)
req.flags |= UPF_BUGGY_UART /*HAVE_CTS_LINE*/;
if (sclk) {
req.flags |= UPF_MAGIC_MULTIPLIER /*USE_SCLK*/;
req.uartclk = sclk;
} else
req.uartclk = TXX9_IMCLK;
early_serial_txx9_setup(&req);
#endif /* CONFIG_SERIAL_TXX9 */
}
#ifdef CONFIG_EARLY_PRINTK
static void null_prom_putchar(char c)
{
}
void (*txx9_prom_putchar)(char c) = null_prom_putchar;
void prom_putchar(char c)
{
txx9_prom_putchar(c);
}
static void __iomem *early_txx9_sio_port;
static void early_txx9_sio_putchar(char c)
{
#define TXX9_SICISR 0x0c
#define TXX9_SITFIFO 0x1c
#define TXX9_SICISR_TXALS 0x00000002
while (!(__raw_readl(early_txx9_sio_port + TXX9_SICISR) &
TXX9_SICISR_TXALS))
;
__raw_writel(c, early_txx9_sio_port + TXX9_SITFIFO);
}
void __init txx9_sio_putchar_init(unsigned long baseaddr)
{
early_txx9_sio_port = ioremap(baseaddr, 0x24);
txx9_prom_putchar = early_txx9_sio_putchar;
}
#endif /* CONFIG_EARLY_PRINTK */
/* wrappers */
void __init plat_mem_setup(void)
{
ioport_resource.start = 0;
ioport_resource.end = ~0UL; /* no limit */
iomem_resource.start = 0;
iomem_resource.end = ~0UL; /* no limit */
/* fallback restart/halt routines */
_machine_restart = (void (*)(char *))txx9_machine_halt;
_machine_halt = txx9_machine_halt;
pm_power_off = txx9_machine_halt;
#ifdef CONFIG_PCI
pcibios_plat_setup = txx9_pcibios_setup;
#endif
txx9_board_vec->mem_setup();
}
void __init arch_init_irq(void)
{
txx9_board_vec->irq_setup();
}
void __init plat_time_init(void)
{
#ifdef CONFIG_CPU_TX49XX
mips_hpt_frequency = txx9_cpu_clock / 2;
#endif
txx9_board_vec->time_init();
}
static void txx9_clk_init(void)
{
struct clk_hw *hw;
int error;
hw = clk_hw_register_fixed_rate(NULL, "gbus", NULL, 0, txx9_gbus_clock);
if (IS_ERR(hw)) {
error = PTR_ERR(hw);
goto fail;
}
hw = clk_hw_register_fixed_factor(NULL, "imbus", "gbus", 0, 1, 2);
error = clk_hw_register_clkdev(hw, "imbus_clk", NULL);
if (error)
goto fail;
#ifdef CONFIG_CPU_TX49XX
if (TX4938_REV_PCODE() == 0x4938) {
hw = clk_hw_register_fixed_factor(NULL, "spi", "gbus", 0, 1, 4);
error = clk_hw_register_clkdev(hw, "spi-baseclk", NULL);
if (error)
goto fail;
}
#endif
return;
fail:
pr_err("Failed to register clocks: %d\n", error);
}
static int __init _txx9_arch_init(void)
{
txx9_clk_init();
if (txx9_board_vec->arch_init)
txx9_board_vec->arch_init();
return 0;
}
arch_initcall(_txx9_arch_init);
static int __init _txx9_device_init(void)
{
if (txx9_board_vec->device_init)
txx9_board_vec->device_init();
return 0;
}
device_initcall(_txx9_device_init);
int (*txx9_irq_dispatch)(int pending);
asmlinkage void plat_irq_dispatch(void)
{
int pending = read_c0_status() & read_c0_cause() & ST0_IM;
int irq = txx9_irq_dispatch(pending);
if (likely(irq >= 0))
do_IRQ(irq);
else
spurious_interrupt();
}
/* see include/asm-mips/mach-tx39xx/mangle-port.h, for example. */
#ifdef NEEDS_TXX9_SWIZZLE_ADDR_B
static unsigned long __swizzle_addr_none(unsigned long port)
{
return port;
}
unsigned long (*__swizzle_addr_b)(unsigned long port) = __swizzle_addr_none;
EXPORT_SYMBOL(__swizzle_addr_b);
#endif
#ifdef NEEDS_TXX9_IOSWABW
static u16 ioswabw_default(volatile u16 *a, u16 x)
{
return le16_to_cpu(x);
}
static u16 __mem_ioswabw_default(volatile u16 *a, u16 x)
{
return x;
}
u16 (*ioswabw)(volatile u16 *a, u16 x) = ioswabw_default;
EXPORT_SYMBOL(ioswabw);
u16 (*__mem_ioswabw)(volatile u16 *a, u16 x) = __mem_ioswabw_default;
EXPORT_SYMBOL(__mem_ioswabw);
#endif
void __init txx9_physmap_flash_init(int no, unsigned long addr,
unsigned long size,
const struct physmap_flash_data *pdata)
{
#if IS_ENABLED(CONFIG_MTD_PHYSMAP)
struct resource res = {
.start = addr,
.end = addr + size - 1,
.flags = IORESOURCE_MEM,
};
struct platform_device *pdev;
static struct mtd_partition parts[2];
struct physmap_flash_data pdata_part;
/* If this area contained boot area, make separate partition */
if (pdata->nr_parts == 0 && !pdata->parts &&
addr < 0x1fc00000 && addr + size > 0x1fc00000 &&
!parts[0].name) {
parts[0].name = "boot";
parts[0].offset = 0x1fc00000 - addr;
parts[0].size = addr + size - 0x1fc00000;
parts[1].name = "user";
parts[1].offset = 0;
parts[1].size = 0x1fc00000 - addr;
pdata_part = *pdata;
pdata_part.nr_parts = ARRAY_SIZE(parts);
pdata_part.parts = parts;
pdata = &pdata_part;
}
pdev = platform_device_alloc("physmap-flash", no);
if (!pdev ||
platform_device_add_resources(pdev, &res, 1) ||
platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
platform_device_add(pdev))
platform_device_put(pdev);
#endif
}
void __init txx9_ndfmc_init(unsigned long baseaddr,
const struct txx9ndfmc_platform_data *pdata)
{
#if IS_ENABLED(CONFIG_MTD_NAND_TXX9NDFMC)
struct resource res = {
.start = baseaddr,
.end = baseaddr + 0x1000 - 1,
.flags = IORESOURCE_MEM,
};
struct platform_device *pdev = platform_device_alloc("txx9ndfmc", -1);
if (!pdev ||
platform_device_add_resources(pdev, &res, 1) ||
platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
platform_device_add(pdev))
platform_device_put(pdev);
#endif
}
#if IS_ENABLED(CONFIG_LEDS_GPIO)
static DEFINE_SPINLOCK(txx9_iocled_lock);
#define TXX9_IOCLED_MAXLEDS 8
struct txx9_iocled_data {
struct gpio_chip chip;
u8 cur_val;
void __iomem *mmioaddr;
struct gpio_led_platform_data pdata;
struct gpio_led leds[TXX9_IOCLED_MAXLEDS];
char names[TXX9_IOCLED_MAXLEDS][32];
};
static int txx9_iocled_get(struct gpio_chip *chip, unsigned int offset)
{
struct txx9_iocled_data *data = gpiochip_get_data(chip);
return !!(data->cur_val & (1 << offset));
}
static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset,
int value)
{
struct txx9_iocled_data *data = gpiochip_get_data(chip);
unsigned long flags;
spin_lock_irqsave(&txx9_iocled_lock, flags);
if (value)
data->cur_val |= 1 << offset;
else
data->cur_val &= ~(1 << offset);
writeb(data->cur_val, data->mmioaddr);
mmiowb();
spin_unlock_irqrestore(&txx9_iocled_lock, flags);
}
static int txx9_iocled_dir_in(struct gpio_chip *chip, unsigned int offset)
{
return 0;
}
static int txx9_iocled_dir_out(struct gpio_chip *chip, unsigned int offset,
int value)
{
txx9_iocled_set(chip, offset, value);
return 0;
}
void __init txx9_iocled_init(unsigned long baseaddr,
int basenum, unsigned int num, int lowactive,
const char *color, char **deftriggers)
{
struct txx9_iocled_data *iocled;
struct platform_device *pdev;
int i;
static char *default_triggers[] __initdata = {
"heartbeat",
"disk-activity",
"nand-disk",
NULL,
};
if (!deftriggers)
deftriggers = default_triggers;
iocled = kzalloc(sizeof(*iocled), GFP_KERNEL);
if (!iocled)
return;
iocled->mmioaddr = ioremap(baseaddr, 1);
if (!iocled->mmioaddr)
goto out_free;
iocled->chip.get = txx9_iocled_get;
iocled->chip.set = txx9_iocled_set;
iocled->chip.direction_input = txx9_iocled_dir_in;
iocled->chip.direction_output = txx9_iocled_dir_out;
iocled->chip.label = "iocled";
iocled->chip.base = basenum;
iocled->chip.ngpio = num;
if (gpiochip_add_data(&iocled->chip, iocled))
goto out_unmap;
if (basenum < 0)
basenum = iocled->chip.base;
pdev = platform_device_alloc("leds-gpio", basenum);
if (!pdev)
goto out_gpio;
iocled->pdata.num_leds = num;
iocled->pdata.leds = iocled->leds;
for (i = 0; i < num; i++) {
struct gpio_led *led = &iocled->leds[i];
snprintf(iocled->names[i], sizeof(iocled->names[i]),
"iocled:%s:%u", color, i);
led->name = iocled->names[i];
led->gpio = basenum + i;
led->active_low = lowactive;
if (deftriggers && *deftriggers)
led->default_trigger = *deftriggers++;
}
pdev->dev.platform_data = &iocled->pdata;
if (platform_device_add(pdev))
goto out_pdev;
return;
out_pdev:
platform_device_put(pdev);
out_gpio:
gpiochip_remove(&iocled->chip);
out_unmap:
iounmap(iocled->mmioaddr);
out_free:
kfree(iocled);
}
#else /* CONFIG_LEDS_GPIO */
void __init txx9_iocled_init(unsigned long baseaddr,
int basenum, unsigned int num, int lowactive,
const char *color, char **deftriggers)
{
}
#endif /* CONFIG_LEDS_GPIO */
void __init txx9_dmac_init(int id, unsigned long baseaddr, int irq,
const struct txx9dmac_platform_data *pdata)
{
#if IS_ENABLED(CONFIG_TXX9_DMAC)
struct resource res[] = {
{
.start = baseaddr,
.end = baseaddr + 0x800 - 1,
.flags = IORESOURCE_MEM,
#ifndef CONFIG_MACH_TX49XX
}, {
.start = irq,
.flags = IORESOURCE_IRQ,
#endif
}
};
#ifdef CONFIG_MACH_TX49XX
struct resource chan_res[] = {
{
.flags = IORESOURCE_IRQ,
}
};
#endif
struct platform_device *pdev = platform_device_alloc("txx9dmac", id);
struct txx9dmac_chan_platform_data cpdata;
int i;
if (!pdev ||
platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) ||
platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
platform_device_add(pdev)) {
platform_device_put(pdev);
return;
}
memset(&cpdata, 0, sizeof(cpdata));
cpdata.dmac_dev = pdev;
for (i = 0; i < TXX9_DMA_MAX_NR_CHANNELS; i++) {
#ifdef CONFIG_MACH_TX49XX
chan_res[0].start = irq + i;
#endif
pdev = platform_device_alloc("txx9dmac-chan",
id * TXX9_DMA_MAX_NR_CHANNELS + i);
if (!pdev ||
#ifdef CONFIG_MACH_TX49XX
platform_device_add_resources(pdev, chan_res,
ARRAY_SIZE(chan_res)) ||
#endif
platform_device_add_data(pdev, &cpdata, sizeof(cpdata)) ||
platform_device_add(pdev))
platform_device_put(pdev);
}
#endif
}
void __init txx9_aclc_init(unsigned long baseaddr, int irq,
unsigned int dmac_id,
unsigned int dma_chan_out,
unsigned int dma_chan_in)
{
#if IS_ENABLED(CONFIG_SND_SOC_TXX9ACLC)
unsigned int dma_base = dmac_id * TXX9_DMA_MAX_NR_CHANNELS;
struct resource res[] = {
{
.start = baseaddr,
.end = baseaddr + 0x100 - 1,
.flags = IORESOURCE_MEM,
}, {
.start = irq,
.flags = IORESOURCE_IRQ,
}, {
.name = "txx9dmac-chan",
.start = dma_base + dma_chan_out,
.flags = IORESOURCE_DMA,
}, {
.name = "txx9dmac-chan",
.start = dma_base + dma_chan_in,
.flags = IORESOURCE_DMA,
}
};
struct platform_device *pdev =
platform_device_alloc("txx9aclc-ac97", -1);
if (!pdev ||
platform_device_add_resources(pdev, res, ARRAY_SIZE(res)) ||
platform_device_add(pdev))
platform_device_put(pdev);
#endif
}
static struct bus_type txx9_sramc_subsys = {
.name = "txx9_sram",
.dev_name = "txx9_sram",
};
struct txx9_sramc_dev {
struct device dev;
struct bin_attribute bindata_attr;
void __iomem *base;
};
static ssize_t txx9_sram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
{
struct txx9_sramc_dev *dev = bin_attr->private;
size_t ramsize = bin_attr->size;
if (pos >= ramsize)
return 0;
if (pos + size > ramsize)
size = ramsize - pos;
memcpy_fromio(buf, dev->base + pos, size);
return size;
}
static ssize_t txx9_sram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
{
struct txx9_sramc_dev *dev = bin_attr->private;
size_t ramsize = bin_attr->size;
if (pos >= ramsize)
return 0;
if (pos + size > ramsize)
size = ramsize - pos;
memcpy_toio(dev->base + pos, buf, size);
return size;
}
static void txx9_device_release(struct device *dev)
{
struct txx9_sramc_dev *tdev;
tdev = container_of(dev, struct txx9_sramc_dev, dev);
kfree(tdev);
}
void __init txx9_sramc_init(struct resource *r)
{
struct txx9_sramc_dev *dev;
size_t size;
int err;
err = subsys_system_register(&txx9_sramc_subsys, NULL);
if (err)
return;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return;
size = resource_size(r);
dev->base = ioremap(r->start, size);
if (!dev->base) {
kfree(dev);
return;
}
dev->dev.release = &txx9_device_release;
dev->dev.bus = &txx9_sramc_subsys;
sysfs_bin_attr_init(&dev->bindata_attr);
dev->bindata_attr.attr.name = "bindata";
dev->bindata_attr.attr.mode = S_IRUSR | S_IWUSR;
dev->bindata_attr.read = txx9_sram_read;
dev->bindata_attr.write = txx9_sram_write;
dev->bindata_attr.size = size;
dev->bindata_attr.private = dev;
err = device_register(&dev->dev);
if (err)
goto exit_put;
err = sysfs_create_bin_file(&dev->dev.kobj, &dev->bindata_attr);
if (err) {
iounmap(dev->base);
device_unregister(&dev->dev);
}
return;
exit_put:
iounmap(dev->base);
put_device(&dev->dev);
}