2008-07-10 23:33:08 +08:00
|
|
|
/*
|
|
|
|
* 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>
|
2008-07-11 22:27:54 +08:00
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/string.h>
|
2017-01-29 10:05:57 +08:00
|
|
|
#include <linux/export.h>
|
2016-09-11 16:59:58 +08:00
|
|
|
#include <linux/clk-provider.h>
|
|
|
|
#include <linux/clkdev.h>
|
2008-07-11 22:27:54 +08:00
|
|
|
#include <linux/err.h>
|
2015-12-08 21:40:40 +08:00
|
|
|
#include <linux/gpio/driver.h>
|
2008-07-23 23:25:18 +08:00
|
|
|
#include <linux/platform_device.h>
|
2018-07-10 04:09:40 +08:00
|
|
|
#include <linux/platform_data/txx9/ndfmc.h>
|
2008-07-25 22:08:06 +08:00
|
|
|
#include <linux/serial_core.h>
|
2008-08-19 21:55:11 +08:00
|
|
|
#include <linux/mtd/physmap.h>
|
2008-09-01 21:22:38 +08:00
|
|
|
#include <linux/leds.h>
|
2011-12-22 07:09:54 +08:00
|
|
|
#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 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2019-04-19 06:20:22 +08:00
|
|
|
#include <linux/io.h>
|
2010-10-07 21:08:54 +08:00
|
|
|
#include <linux/irq.h>
|
2008-07-11 22:27:54 +08:00
|
|
|
#include <asm/bootinfo.h>
|
2013-05-21 22:59:19 +08:00
|
|
|
#include <asm/idle.h>
|
2008-07-19 00:51:52 +08:00
|
|
|
#include <asm/time.h>
|
2008-07-23 23:25:17 +08:00
|
|
|
#include <asm/reboot.h>
|
2008-08-19 21:55:09 +08:00
|
|
|
#include <asm/r4kcache.h>
|
2018-07-13 23:51:56 +08:00
|
|
|
#include <asm/setup.h>
|
2008-07-10 23:33:08 +08:00
|
|
|
#include <asm/txx9/generic.h>
|
2008-07-23 23:25:15 +08:00
|
|
|
#include <asm/txx9/pci.h>
|
2008-08-19 21:55:15 +08:00
|
|
|
#include <asm/txx9tmr.h>
|
2009-04-22 23:40:31 +08:00
|
|
|
#include <asm/txx9/dmac.h>
|
2008-07-11 22:27:54 +08:00
|
|
|
#ifdef CONFIG_CPU_TX49XX
|
|
|
|
#include <asm/txx9/tx4938.h>
|
|
|
|
#endif
|
2008-07-10 23:33:08 +08:00
|
|
|
|
|
|
|
/* EBUSC settings of TX4927, etc. */
|
|
|
|
struct resource txx9_ce_res[8];
|
|
|
|
static char txx9_ce_res_name[8][4]; /* "CEn" */
|
|
|
|
|
|
|
|
/* pcode, internal register */
|
2008-07-19 00:51:47 +08:00
|
|
|
unsigned int txx9_pcode;
|
2008-07-10 23:33:08 +08:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
2008-08-26 20:29:58 +08:00
|
|
|
txx9_pcode = pcode;
|
2008-07-10 23:33:08 +08:00
|
|
|
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;
|
2008-07-11 22:27:54 +08:00
|
|
|
|
2008-08-19 21:55:10 +08:00
|
|
|
#ifdef CONFIG_CPU_TX39XX
|
|
|
|
/* don't enable by default - see errata */
|
|
|
|
int txx9_ccfg_toeon __initdata;
|
|
|
|
#else
|
2008-07-19 00:51:47 +08:00
|
|
|
int txx9_ccfg_toeon __initdata = 1;
|
2008-08-19 21:55:10 +08:00
|
|
|
#endif
|
2008-07-11 22:27:54 +08:00
|
|
|
|
2008-08-19 21:55:08 +08:00
|
|
|
#define BOARD_VEC(board) extern struct txx9_board_vec board;
|
|
|
|
#include <asm/txx9/boards.h>
|
|
|
|
#undef BOARD_VEC
|
2008-07-11 22:27:54 +08:00
|
|
|
|
|
|
|
struct txx9_board_vec *txx9_board_vec __initdata;
|
|
|
|
static char txx9_system_type[32];
|
|
|
|
|
2008-08-19 21:55:08 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-08-19 21:55:06 +08:00
|
|
|
static void __init prom_init_cmdline(void)
|
2008-07-11 22:27:54 +08:00
|
|
|
{
|
2008-10-27 22:25:49 +08:00
|
|
|
int argc;
|
|
|
|
int *argv32;
|
2008-07-11 22:27:54 +08:00
|
|
|
int i; /* Always ignore the "-c" at argv[0] */
|
|
|
|
|
2008-10-27 22:25:49 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-08-19 21:55:06 +08:00
|
|
|
arcs_cmdline[0] = '\0';
|
2008-07-11 22:27:54 +08:00
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) {
|
2008-08-19 21:55:06 +08:00
|
|
|
char *str = (char *)(long)argv32[i];
|
2008-07-11 22:27:54 +08:00
|
|
|
if (i != 1)
|
|
|
|
strcat(arcs_cmdline, " ");
|
2008-08-19 21:55:06 +08:00
|
|
|
if (strchr(str, ' ')) {
|
|
|
|
strcat(arcs_cmdline, "\"");
|
|
|
|
strcat(arcs_cmdline, str);
|
|
|
|
strcat(arcs_cmdline, "\"");
|
|
|
|
} else
|
|
|
|
strcat(arcs_cmdline, str);
|
|
|
|
}
|
2008-07-11 22:27:54 +08:00
|
|
|
}
|
|
|
|
|
2008-08-19 21:55:09 +08:00
|
|
|
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
|
|
|
|
|
2008-08-19 21:55:08 +08:00
|
|
|
static void __init preprocess_cmdline(void)
|
2008-07-11 22:27:54 +08:00
|
|
|
{
|
2009-10-14 04:43:24 +08:00
|
|
|
static char cmdline[COMMAND_LINE_SIZE] __initdata;
|
2008-08-19 21:55:08 +08:00
|
|
|
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) {
|
2014-06-03 23:22:08 +08:00
|
|
|
unsigned int val;
|
|
|
|
if (kstrtouint(str + 10, 10, &val) == 0)
|
2008-08-19 21:55:08 +08:00
|
|
|
txx9_master_clock = val;
|
|
|
|
continue;
|
2008-08-19 21:55:09 +08:00
|
|
|
} else if (strcmp(str, "icdisable") == 0) {
|
|
|
|
txx9_ic_disable = 1;
|
|
|
|
continue;
|
|
|
|
} else if (strcmp(str, "dcdisable") == 0) {
|
|
|
|
txx9_dc_disable = 1;
|
|
|
|
continue;
|
2008-08-19 21:55:10 +08:00
|
|
|
} else if (strcmp(str, "toeoff") == 0) {
|
|
|
|
txx9_ccfg_toeon = 0;
|
|
|
|
continue;
|
|
|
|
} else if (strcmp(str, "toeon") == 0) {
|
|
|
|
txx9_ccfg_toeon = 1;
|
|
|
|
continue;
|
2008-08-19 21:55:08 +08:00
|
|
|
}
|
|
|
|
if (arcs_cmdline[0])
|
|
|
|
strcat(arcs_cmdline, " ");
|
|
|
|
strcat(arcs_cmdline, str);
|
|
|
|
}
|
2008-08-19 21:55:09 +08:00
|
|
|
|
|
|
|
txx9_cache_fixup();
|
2008-08-19 21:55:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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 */
|
2013-08-14 16:57:16 +08:00
|
|
|
#ifdef CONFIG_TOSHIBA_JMR3927
|
2008-07-13 18:51:55 +08:00
|
|
|
txx9_board_vec = &jmr3927_vec;
|
2008-07-11 22:27:54 +08:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_CPU_TX49XX
|
|
|
|
switch (TX4938_REV_PCODE()) {
|
2008-07-17 23:43:48 +08:00
|
|
|
#ifdef CONFIG_TOSHIBA_RBTX4927
|
2008-07-11 22:27:54 +08:00
|
|
|
case 0x4927:
|
2008-07-13 18:51:55 +08:00
|
|
|
txx9_board_vec = &rbtx4927_vec;
|
2008-07-11 22:27:54 +08:00
|
|
|
break;
|
|
|
|
case 0x4937:
|
2008-07-13 18:51:55 +08:00
|
|
|
txx9_board_vec = &rbtx4937_vec;
|
2008-07-11 22:27:54 +08:00
|
|
|
break;
|
2008-07-17 23:43:48 +08:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_TOSHIBA_RBTX4938
|
2008-07-11 22:27:54 +08:00
|
|
|
case 0x4938:
|
2008-07-13 18:51:55 +08:00
|
|
|
txx9_board_vec = &rbtx4938_vec;
|
2008-07-11 22:27:54 +08:00
|
|
|
break;
|
2008-09-01 21:22:40 +08:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_TOSHIBA_RBTX4939
|
|
|
|
case 0x4939:
|
|
|
|
txx9_board_vec = &rbtx4939_vec;
|
|
|
|
break;
|
2008-07-17 23:43:48 +08:00
|
|
|
#endif
|
2008-07-11 22:27:54 +08:00
|
|
|
}
|
|
|
|
#endif
|
2008-08-19 21:55:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void __init prom_init(void)
|
|
|
|
{
|
|
|
|
prom_init_cmdline();
|
|
|
|
preprocess_cmdline();
|
|
|
|
select_board();
|
2008-07-13 18:51:55 +08:00
|
|
|
|
|
|
|
strcpy(txx9_system_type, txx9_board_vec->system);
|
|
|
|
|
2008-07-13 23:15:04 +08:00
|
|
|
txx9_board_vec->prom_init();
|
2008-07-11 22:27:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *get_system_type(void)
|
|
|
|
{
|
|
|
|
return txx9_system_type;
|
|
|
|
}
|
|
|
|
|
2008-08-19 21:55:07 +08:00
|
|
|
const char *__init prom_getenv(const char *name)
|
|
|
|
{
|
2008-10-27 22:25:49 +08:00
|
|
|
const s32 *str;
|
2008-08-19 21:55:07 +08:00
|
|
|
|
2008-10-27 22:25:49 +08:00
|
|
|
if (fw_arg2 < CKSEG0)
|
2008-08-19 21:55:07 +08:00
|
|
|
return NULL;
|
2008-10-27 22:25:49 +08:00
|
|
|
|
|
|
|
str = (const s32 *)fw_arg2;
|
2008-08-19 21:55:07 +08:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2008-07-23 23:25:17 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-23 23:25:18 +08:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2008-08-19 21:55:15 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-07-23 23:25:20 +08:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2008-07-25 22:08:06 +08:00
|
|
|
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 */
|
|
|
|
}
|
|
|
|
|
2008-07-29 21:10:08 +08:00
|
|
|
#ifdef CONFIG_EARLY_PRINTK
|
2013-02-12 04:51:49 +08:00
|
|
|
static void null_prom_putchar(char c)
|
2008-07-29 21:10:08 +08:00
|
|
|
{
|
|
|
|
}
|
2013-02-12 04:51:49 +08:00
|
|
|
void (*txx9_prom_putchar)(char c) = null_prom_putchar;
|
2008-07-29 21:10:08 +08:00
|
|
|
|
2013-02-12 04:51:49 +08:00
|
|
|
void prom_putchar(char c)
|
2008-07-29 21:10:08 +08:00
|
|
|
{
|
|
|
|
txx9_prom_putchar(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __iomem *early_txx9_sio_port;
|
|
|
|
|
2013-02-12 04:51:49 +08:00
|
|
|
static void early_txx9_sio_putchar(char c)
|
2008-07-29 21:10:08 +08:00
|
|
|
{
|
|
|
|
#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 */
|
|
|
|
|
2008-07-11 22:27:54 +08:00
|
|
|
/* wrappers */
|
|
|
|
void __init plat_mem_setup(void)
|
|
|
|
{
|
2008-07-19 00:51:47 +08:00
|
|
|
ioport_resource.start = 0;
|
|
|
|
ioport_resource.end = ~0UL; /* no limit */
|
|
|
|
iomem_resource.start = 0;
|
|
|
|
iomem_resource.end = ~0UL; /* no limit */
|
2008-07-23 23:25:17 +08:00
|
|
|
|
|
|
|
/* fallback restart/halt routines */
|
|
|
|
_machine_restart = (void (*)(char *))txx9_machine_halt;
|
|
|
|
_machine_halt = txx9_machine_halt;
|
|
|
|
pm_power_off = txx9_machine_halt;
|
|
|
|
|
2008-07-23 23:25:15 +08:00
|
|
|
#ifdef CONFIG_PCI
|
|
|
|
pcibios_plat_setup = txx9_pcibios_setup;
|
|
|
|
#endif
|
2008-07-11 22:27:54 +08:00
|
|
|
txx9_board_vec->mem_setup();
|
|
|
|
}
|
|
|
|
|
|
|
|
void __init arch_init_irq(void)
|
|
|
|
{
|
|
|
|
txx9_board_vec->irq_setup();
|
|
|
|
}
|
|
|
|
|
|
|
|
void __init plat_time_init(void)
|
|
|
|
{
|
2008-07-31 21:29:53 +08:00
|
|
|
#ifdef CONFIG_CPU_TX49XX
|
|
|
|
mips_hpt_frequency = txx9_cpu_clock / 2;
|
|
|
|
#endif
|
2008-07-11 22:27:54 +08:00
|
|
|
txx9_board_vec->time_init();
|
|
|
|
}
|
|
|
|
|
2016-09-11 16:59:58 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2008-07-11 22:27:54 +08:00
|
|
|
static int __init _txx9_arch_init(void)
|
|
|
|
{
|
2016-09-11 16:59:58 +08:00
|
|
|
txx9_clk_init();
|
|
|
|
|
2008-07-11 22:27:54 +08:00
|
|
|
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();
|
|
|
|
}
|
2008-07-13 22:37:56 +08:00
|
|
|
|
|
|
|
/* 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
|
2008-08-19 21:55:11 +08:00
|
|
|
|
2008-10-20 23:01:06 +08:00
|
|
|
#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
|
|
|
|
|
2008-08-19 21:55:11 +08:00
|
|
|
void __init txx9_physmap_flash_init(int no, unsigned long addr,
|
|
|
|
unsigned long size,
|
|
|
|
const struct physmap_flash_data *pdata)
|
|
|
|
{
|
2012-02-01 01:19:05 +08:00
|
|
|
#if IS_ENABLED(CONFIG_MTD_PHYSMAP)
|
2008-08-19 21:55:11 +08:00
|
|
|
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;
|
|
|
|
}
|
2011-05-23 17:22:55 +08:00
|
|
|
|
2008-08-19 21:55:11 +08:00
|
|
|
pdev = platform_device_alloc("physmap-flash", no);
|
|
|
|
if (!pdev ||
|
|
|
|
platform_device_add_resources(pdev, &res, 1) ||
|
2009-03-05 04:01:31 +08:00
|
|
|
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)
|
|
|
|
{
|
2012-02-01 01:19:05 +08:00
|
|
|
#if IS_ENABLED(CONFIG_MTD_NAND_TXX9NDFMC)
|
2009-03-05 04:01:31 +08:00
|
|
|
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) ||
|
2008-08-19 21:55:11 +08:00
|
|
|
platform_device_add_data(pdev, pdata, sizeof(*pdata)) ||
|
|
|
|
platform_device_add(pdev))
|
|
|
|
platform_device_put(pdev);
|
|
|
|
#endif
|
|
|
|
}
|
2008-09-01 21:22:38 +08:00
|
|
|
|
2012-02-01 01:19:05 +08:00
|
|
|
#if IS_ENABLED(CONFIG_LEDS_GPIO)
|
2008-09-01 21:22:38 +08:00
|
|
|
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)
|
|
|
|
{
|
2015-12-08 21:40:40 +08:00
|
|
|
struct txx9_iocled_data *data = gpiochip_get_data(chip);
|
2015-12-22 22:41:44 +08:00
|
|
|
return !!(data->cur_val & (1 << offset));
|
2008-09-01 21:22:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void txx9_iocled_set(struct gpio_chip *chip, unsigned int offset,
|
|
|
|
int value)
|
|
|
|
{
|
2015-12-08 21:40:40 +08:00
|
|
|
struct txx9_iocled_data *data = gpiochip_get_data(chip);
|
2008-09-01 21:22:38 +08:00
|
|
|
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",
|
2016-06-10 14:00:00 +08:00
|
|
|
"disk-activity",
|
2008-09-01 21:22:38 +08:00
|
|
|
"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)
|
2009-09-14 03:15:18 +08:00
|
|
|
goto out_free;
|
2008-09-01 21:22:38 +08:00
|
|
|
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;
|
2015-12-08 21:40:40 +08:00
|
|
|
if (gpiochip_add_data(&iocled->chip, iocled))
|
2009-09-14 03:15:18 +08:00
|
|
|
goto out_unmap;
|
2008-09-01 21:22:38 +08:00
|
|
|
if (basenum < 0)
|
|
|
|
basenum = iocled->chip.base;
|
|
|
|
|
|
|
|
pdev = platform_device_alloc("leds-gpio", basenum);
|
|
|
|
if (!pdev)
|
2009-09-14 03:15:18 +08:00
|
|
|
goto out_gpio;
|
2008-09-01 21:22:38 +08:00
|
|
|
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))
|
2009-09-14 03:15:18 +08:00
|
|
|
goto out_pdev;
|
|
|
|
return;
|
2014-07-13 04:30:14 +08:00
|
|
|
|
2009-09-14 03:15:18 +08:00
|
|
|
out_pdev:
|
|
|
|
platform_device_put(pdev);
|
|
|
|
out_gpio:
|
2014-07-13 04:30:14 +08:00
|
|
|
gpiochip_remove(&iocled->chip);
|
2009-09-14 03:15:18 +08:00
|
|
|
out_unmap:
|
|
|
|
iounmap(iocled->mmioaddr);
|
|
|
|
out_free:
|
|
|
|
kfree(iocled);
|
2008-09-01 21:22:38 +08:00
|
|
|
}
|
|
|
|
#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 */
|
2009-04-22 23:40:31 +08:00
|
|
|
|
|
|
|
void __init txx9_dmac_init(int id, unsigned long baseaddr, int irq,
|
|
|
|
const struct txx9dmac_platform_data *pdata)
|
|
|
|
{
|
2012-02-01 01:19:05 +08:00
|
|
|
#if IS_ENABLED(CONFIG_TXX9_DMAC)
|
2009-04-22 23:40:31 +08:00
|
|
|
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
|
|
|
|
}
|
2009-05-19 21:12:22 +08:00
|
|
|
|
|
|
|
void __init txx9_aclc_init(unsigned long baseaddr, int irq,
|
|
|
|
unsigned int dmac_id,
|
|
|
|
unsigned int dma_chan_out,
|
|
|
|
unsigned int dma_chan_in)
|
|
|
|
{
|
2012-02-01 01:19:05 +08:00
|
|
|
#if IS_ENABLED(CONFIG_SND_SOC_TXX9ACLC)
|
2009-05-19 21:12:22 +08:00
|
|
|
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
|
|
|
|
}
|
2009-05-25 21:04:02 +08:00
|
|
|
|
2011-12-22 07:09:54 +08:00
|
|
|
static struct bus_type txx9_sramc_subsys = {
|
|
|
|
.name = "txx9_sram",
|
|
|
|
.dev_name = "txx9_sram",
|
|
|
|
};
|
2009-05-25 21:04:02 +08:00
|
|
|
|
2011-12-22 07:09:54 +08:00
|
|
|
struct txx9_sramc_dev {
|
|
|
|
struct device dev;
|
2009-05-25 21:04:02 +08:00
|
|
|
struct bin_attribute bindata_attr;
|
|
|
|
void __iomem *base;
|
|
|
|
};
|
|
|
|
|
2010-05-13 09:28:57 +08:00
|
|
|
static ssize_t txx9_sram_read(struct file *filp, struct kobject *kobj,
|
2009-05-25 21:04:02 +08:00
|
|
|
struct bin_attribute *bin_attr,
|
|
|
|
char *buf, loff_t pos, size_t size)
|
|
|
|
{
|
2011-12-22 07:09:54 +08:00
|
|
|
struct txx9_sramc_dev *dev = bin_attr->private;
|
2009-05-25 21:04:02 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-05-13 09:28:57 +08:00
|
|
|
static ssize_t txx9_sram_write(struct file *filp, struct kobject *kobj,
|
2009-05-25 21:04:02 +08:00
|
|
|
struct bin_attribute *bin_attr,
|
|
|
|
char *buf, loff_t pos, size_t size)
|
|
|
|
{
|
2011-12-22 07:09:54 +08:00
|
|
|
struct txx9_sramc_dev *dev = bin_attr->private;
|
2009-05-25 21:04:02 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-12-19 23:03:25 +08:00
|
|
|
static void txx9_device_release(struct device *dev)
|
|
|
|
{
|
|
|
|
struct txx9_sramc_dev *tdev;
|
|
|
|
|
|
|
|
tdev = container_of(dev, struct txx9_sramc_dev, dev);
|
|
|
|
kfree(tdev);
|
|
|
|
}
|
|
|
|
|
2009-05-25 21:04:02 +08:00
|
|
|
void __init txx9_sramc_init(struct resource *r)
|
|
|
|
{
|
2011-12-22 07:09:54 +08:00
|
|
|
struct txx9_sramc_dev *dev;
|
2009-05-25 21:04:02 +08:00
|
|
|
size_t size;
|
|
|
|
int err;
|
|
|
|
|
2011-12-22 07:09:54 +08:00
|
|
|
err = subsys_system_register(&txx9_sramc_subsys, NULL);
|
|
|
|
if (err)
|
|
|
|
return;
|
2009-05-25 21:04:02 +08:00
|
|
|
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
|
|
|
if (!dev)
|
|
|
|
return;
|
|
|
|
size = resource_size(r);
|
|
|
|
dev->base = ioremap(r->start, size);
|
2013-12-19 23:03:25 +08:00
|
|
|
if (!dev->base) {
|
|
|
|
kfree(dev);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dev->dev.release = &txx9_device_release;
|
2011-12-22 07:09:54 +08:00
|
|
|
dev->dev.bus = &txx9_sramc_subsys;
|
2010-03-15 08:29:41 +08:00
|
|
|
sysfs_bin_attr_init(&dev->bindata_attr);
|
2009-05-25 21:04:02 +08:00
|
|
|
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;
|
2011-12-22 07:09:54 +08:00
|
|
|
err = device_register(&dev->dev);
|
2009-05-25 21:04:02 +08:00
|
|
|
if (err)
|
2013-12-19 23:03:25 +08:00
|
|
|
goto exit_put;
|
2009-05-25 21:04:02 +08:00
|
|
|
err = sysfs_create_bin_file(&dev->dev.kobj, &dev->bindata_attr);
|
|
|
|
if (err) {
|
2013-12-19 23:03:25 +08:00
|
|
|
iounmap(dev->base);
|
2018-09-06 12:19:19 +08:00
|
|
|
device_unregister(&dev->dev);
|
2009-05-25 21:04:02 +08:00
|
|
|
}
|
2013-12-19 23:03:25 +08:00
|
|
|
return;
|
|
|
|
exit_put:
|
2018-09-06 12:19:19 +08:00
|
|
|
iounmap(dev->base);
|
2013-12-19 23:03:25 +08:00
|
|
|
put_device(&dev->dev);
|
2009-05-25 21:04:02 +08:00
|
|
|
}
|