aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mcs814x/files-3.18/arch/arm/mach-mcs814x/common.c
blob: 3f1be1fe2d3e0e629752e65d747b893217c64db9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
 * arch/arm/mach-mcs814x/common.c
 *
 * Core functions for Moschip MCS814x SoCs
 *
 * This file is licensed under the terms of the GNU General Public
 * License version 2.  This program is licensed "as is" without any
 * warranty of any kind, whether express or implied.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/reboot.h>

#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/mcs814x.h>
#include <mach/cpu.h>
#include <asm/pgtable.h>
#include <asm/mach/map.h>

void __iomem *mcs814x_sysdbg_base;

static struct map_desc mcs814x_io_desc[] __initdata = {
	{
		.virtual	= MCS814X_IO_BASE,
		.pfn		= __phys_to_pfn(MCS814X_IO_START),
		.length		= MCS814X_IO_SIZE,
		.type		= MT_DEVICE
	},
};

struct cpu_mode {
	const char *name;
	int gpio_start;
	int gpio_end;
};

static const struct cpu_mode cpu_modes[] = {
	{
		.name		= "I2S",
		.gpio_start	= 4,
		.gpio_end	= 8,
	},
	{
		.name		= "UART",
		.gpio_start	= 4,
		.gpio_end	= 9,
	},
	{
		.name		= "External MII",
		.gpio_start	= 0,
		.gpio_end	= 16,
	},
	{
		.name		= "Normal",
		.gpio_start	= -1,
		.gpio_end	= -1,
	},
};

static void mcs814x_eth_hardware_filter_set(u8 value)
{
	u32 reg;

	reg = readl_relaxed(MCS814X_VIRT_BASE + MCS814X_DBGLED);
	if (value)
		reg |= 0x80;
	else
		reg &= ~0x80;
	writel_relaxed(reg, MCS814X_VIRT_BASE + MCS814X_DBGLED);
}

static void mcs814x_eth_led_cfg_set(u8 cfg)
{
	u32 reg;

	reg = readl_relaxed(mcs814x_sysdbg_base + SYSDBG_BS2);
	reg &= ~LED_CFG_MASK;
	reg |= cfg;
	writel_relaxed(reg, mcs814x_sysdbg_base + SYSDBG_BS2);
}

static void mcs814x_eth_buffer_shifting_set(u8 value)
{
	u8 reg;

	reg = readb_relaxed(mcs814x_sysdbg_base + SYSDBG_SYSCTL_MAC);
	if (value)
		reg |= BUF_SHIFT_BIT;
	else
		reg &= ~BUF_SHIFT_BIT;
	writeb_relaxed(reg, mcs814x_sysdbg_base + SYSDBG_SYSCTL_MAC);
}

static struct of_device_id mcs814x_eth_ids[] __initdata = {
	{ .compatible = "moschip,nuport-mac", },
	{ /* sentinel */ },
};

/* Configure platform specific knobs based on ethernet device node
 * properties */
static void mcs814x_eth_init(void)
{
	struct device_node *np;
	const unsigned int *intspec;

	np = of_find_matching_node(NULL, mcs814x_eth_ids);
	if (!np)
		return;

	/* hardware filter must always be enabled */
	mcs814x_eth_hardware_filter_set(1);

	intspec = of_get_property(np, "nuport-mac,buffer-shifting", NULL);
	if (!intspec)
		mcs814x_eth_buffer_shifting_set(0);
	else
		mcs814x_eth_buffer_shifting_set(1);

	intspec = of_get_property(np, "nuport-mac,link-activity", NULL);
	if (intspec)
		mcs814x_eth_led_cfg_set(be32_to_cpup(intspec));

	of_node_put(np);
}

void __init mcs814x_init_machine(void)
{
	u32 bs2, cpu_mode;
	int gpio;

	bs2 = readl_relaxed(mcs814x_sysdbg_base + SYSDBG_BS2);
	cpu_mode = (bs2 >> CPU_MODE_SHIFT) & CPU_MODE_MASK;

	pr_info("CPU mode: %s\n", cpu_modes[cpu_mode].name);

	/* request the gpios since the pins are muxed for functionnality */
	for (gpio = cpu_modes[cpu_mode].gpio_start;
		gpio == cpu_modes[cpu_mode].gpio_end; gpio++) {
		if (gpio != -1)
			gpio_request(gpio, cpu_modes[cpu_mode].name);
	}

	mcs814x_eth_init();
}

void __init mcs814x_map_io(void)
{
	iotable_init(mcs814x_io_desc, ARRAY_SIZE(mcs814x_io_desc));

	mcs814x_sysdbg_base = ioremap(MCS814X_IO_START + MCS814X_SYSDBG,
					MCS814X_SYSDBG_SIZE);
	if (!mcs814x_sysdbg_base)
		panic("unable to remap sysdbg base");
}

void mcs814x_restart(enum reboot_mode mode, const char *cmd)
{
	writel_relaxed(~(1 << 31), mcs814x_sysdbg_base);
}