summaryrefslogtreecommitdiff
path: root/arch/mips/n64/init.c
blob: dfbd864f46670058f876279c3860f96355ba894c (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
// SPDX-License-Identifier: GPL-2.0
/*
 *  Nintendo 64 init.
 *
 *  Copyright (C) 2021	Lauri Kasanen
 */
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/memblock.h>
#include <linux/platform_device.h>
#include <linux/platform_data/simplefb.h>
#include <linux/string.h>

#include <asm/bootinfo.h>
#include <asm/fw/fw.h>
#include <asm/time.h>

#define IO_MEM_RESOURCE_START	0UL
#define IO_MEM_RESOURCE_END	0x1fffffffUL

/*
 * System-specifc irq names for clarity
 */
#define MIPS_CPU_IRQ(x)		(MIPS_CPU_IRQ_BASE + (x))
#define MIPS_SOFTINT0_IRQ	MIPS_CPU_IRQ(0)
#define MIPS_SOFTINT1_IRQ	MIPS_CPU_IRQ(1)
#define RCP_IRQ			MIPS_CPU_IRQ(2)
#define CART_IRQ		MIPS_CPU_IRQ(3)
#define PRENMI_IRQ		MIPS_CPU_IRQ(4)
#define RDBR_IRQ		MIPS_CPU_IRQ(5)
#define RDBW_IRQ		MIPS_CPU_IRQ(6)
#define TIMER_IRQ		MIPS_CPU_IRQ(7)

static void __init iomem_resource_init(void)
{
	iomem_resource.start = IO_MEM_RESOURCE_START;
	iomem_resource.end = IO_MEM_RESOURCE_END;
}

const char *get_system_type(void)
{
	return "Nintendo 64";
}

void __init prom_init(void)
{
	fw_init_cmdline();
}

#define W 320
#define H 240
#define REG_BASE ((u32 *) CKSEG1ADDR(0x4400000))

static void __init n64rdp_write_reg(const u8 reg, const u32 value)
{
	__raw_writel(value, REG_BASE + reg);
}

#undef REG_BASE

static const u32 ntsc_320[] __initconst = {
	0x00013212, 0x00000000, 0x00000140, 0x00000200,
	0x00000000, 0x03e52239, 0x0000020d, 0x00000c15,
	0x0c150c15, 0x006c02ec, 0x002501ff, 0x000e0204,
	0x00000200, 0x00000400
};

#define MI_REG_BASE 0x4300000
#define NUM_MI_REGS 4
#define AI_REG_BASE 0x4500000
#define NUM_AI_REGS 6
#define PI_REG_BASE 0x4600000
#define NUM_PI_REGS 5
#define SI_REG_BASE 0x4800000
#define NUM_SI_REGS 7

static int __init n64_platform_init(void)
{
	static const char simplefb_resname[] = "FB";
	static const struct simplefb_platform_data mode = {
		.width = W,
		.height = H,
		.stride = W * 2,
		.format = "r5g5b5a1"
	};
	struct resource res[3];
	void *orig;
	unsigned long phys;
	unsigned i;

	memset(res, 0, sizeof(struct resource) * 3);
	res[0].flags = IORESOURCE_MEM;
	res[0].start = MI_REG_BASE;
	res[0].end = MI_REG_BASE + NUM_MI_REGS * 4 - 1;

	res[1].flags = IORESOURCE_MEM;
	res[1].start = AI_REG_BASE;
	res[1].end = AI_REG_BASE + NUM_AI_REGS * 4 - 1;

	res[2].flags = IORESOURCE_IRQ;
	res[2].start = RCP_IRQ;
	res[2].end = RCP_IRQ;

	platform_device_register_simple("n64audio", -1, res, 3);

	memset(&res[0], 0, sizeof(res[0]));
	res[0].flags = IORESOURCE_MEM;
	res[0].start = PI_REG_BASE;
	res[0].end = PI_REG_BASE + NUM_PI_REGS * 4 - 1;

	platform_device_register_simple("n64cart", -1, res, 1);

	memset(&res[0], 0, sizeof(res[0]));
	res[0].flags = IORESOURCE_MEM;
	res[0].start = SI_REG_BASE;
	res[0].end = SI_REG_BASE + NUM_SI_REGS * 4 - 1;

	platform_device_register_simple("n64joy", -1, res, 1);

	/* The framebuffer needs 64-byte alignment */
	orig = kzalloc(W * H * 2 + 63, GFP_DMA | GFP_KERNEL);
	if (!orig)
		return -ENOMEM;
	phys = virt_to_phys(orig);
	phys += 63;
	phys &= ~63;

	for (i = 0; i < ARRAY_SIZE(ntsc_320); i++) {
		if (i == 1)
			n64rdp_write_reg(i, phys);
		else
			n64rdp_write_reg(i, ntsc_320[i]);
	}

	/* setup IORESOURCE_MEM as framebuffer memory */
	memset(&res[0], 0, sizeof(res[0]));
	res[0].flags = IORESOURCE_MEM;
	res[0].name = simplefb_resname;
	res[0].start = phys;
	res[0].end = phys + W * H * 2 - 1;

	platform_device_register_resndata(NULL, "simple-framebuffer", 0,
					  &res[0], 1, &mode, sizeof(mode));

	return 0;
}

#undef W
#undef H

arch_initcall(n64_platform_init);

void __init plat_mem_setup(void)
{
	iomem_resource_init();
	memblock_add(0x0, 8 * 1024 * 1024); /* Bootloader blocks the 4mb config */
}

void __init plat_time_init(void)
{
	/* 93.75 MHz cpu, count register runs at half rate */
	mips_hpt_frequency = 93750000 / 2;
}