1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/init.h>
3 #include <linux/types.h>
4 #include <linux/kernel.h>
5 #include <linux/mm.h>
6 #include <linux/rtc.h>
7 #include <linux/interrupt.h>
8
9 #include <asm/setup.h>
10 #include <asm/bootinfo.h>
11 #include <asm/bootinfo-apollo.h>
12 #include <asm/byteorder.h>
13 #include <asm/apollohw.h>
14 #include <asm/irq.h>
15 #include <asm/machdep.h>
16 #include <asm/config.h>
17
18 #include "apollo.h"
19
20 u_long sio01_physaddr;
21 u_long sio23_physaddr;
22 u_long rtc_physaddr;
23 u_long pica_physaddr;
24 u_long picb_physaddr;
25 u_long cpuctrl_physaddr;
26 u_long timer_physaddr;
27 u_long apollo_model;
28
29 extern void dn_sched_init(void);
30 extern int dn_dummy_hwclk(int, struct rtc_time *);
31 static void dn_dummy_reset(void);
32 #ifdef CONFIG_HEARTBEAT
33 static void dn_heartbeat(int on);
34 #endif
35 static irqreturn_t dn_timer_int(int irq,void *);
36 static void dn_get_model(char *model);
37 static const char *apollo_models[] = {
38 [APOLLO_DN3000-APOLLO_DN3000] = "DN3000 (Otter)",
39 [APOLLO_DN3010-APOLLO_DN3000] = "DN3010 (Otter)",
40 [APOLLO_DN3500-APOLLO_DN3000] = "DN3500 (Cougar II)",
41 [APOLLO_DN4000-APOLLO_DN3000] = "DN4000 (Mink)",
42 [APOLLO_DN4500-APOLLO_DN3000] = "DN4500 (Roadrunner)"
43 };
44
apollo_parse_bootinfo(const struct bi_record * record)45 int __init apollo_parse_bootinfo(const struct bi_record *record)
46 {
47 int unknown = 0;
48 const void *data = record->data;
49
50 switch (be16_to_cpu(record->tag)) {
51 case BI_APOLLO_MODEL:
52 apollo_model = be32_to_cpup(data);
53 break;
54
55 default:
56 unknown=1;
57 }
58
59 return unknown;
60 }
61
dn_setup_model(void)62 static void __init dn_setup_model(void)
63 {
64 pr_info("Apollo hardware found: [%s]\n",
65 apollo_models[apollo_model - APOLLO_DN3000]);
66
67 switch(apollo_model) {
68 case APOLLO_UNKNOWN:
69 panic("Unknown apollo model");
70 break;
71 case APOLLO_DN3000:
72 case APOLLO_DN3010:
73 sio01_physaddr=SAU8_SIO01_PHYSADDR;
74 rtc_physaddr=SAU8_RTC_PHYSADDR;
75 pica_physaddr=SAU8_PICA;
76 picb_physaddr=SAU8_PICB;
77 cpuctrl_physaddr=SAU8_CPUCTRL;
78 timer_physaddr=SAU8_TIMER;
79 break;
80 case APOLLO_DN4000:
81 sio01_physaddr=SAU7_SIO01_PHYSADDR;
82 sio23_physaddr=SAU7_SIO23_PHYSADDR;
83 rtc_physaddr=SAU7_RTC_PHYSADDR;
84 pica_physaddr=SAU7_PICA;
85 picb_physaddr=SAU7_PICB;
86 cpuctrl_physaddr=SAU7_CPUCTRL;
87 timer_physaddr=SAU7_TIMER;
88 break;
89 case APOLLO_DN4500:
90 panic("Apollo model not yet supported");
91 break;
92 case APOLLO_DN3500:
93 sio01_physaddr=SAU7_SIO01_PHYSADDR;
94 sio23_physaddr=SAU7_SIO23_PHYSADDR;
95 rtc_physaddr=SAU7_RTC_PHYSADDR;
96 pica_physaddr=SAU7_PICA;
97 picb_physaddr=SAU7_PICB;
98 cpuctrl_physaddr=SAU7_CPUCTRL;
99 timer_physaddr=SAU7_TIMER;
100 break;
101 default:
102 panic("Undefined apollo model");
103 break;
104 }
105
106
107 }
108
dn_serial_print(const char * str)109 static void dn_serial_print(const char *str)
110 {
111 while (*str) {
112 if (*str == '\n') {
113 sio01.rhrb_thrb = (unsigned char)'\r';
114 while (!(sio01.srb_csrb & 0x4))
115 ;
116 }
117 sio01.rhrb_thrb = (unsigned char)*str++;
118 while (!(sio01.srb_csrb & 0x4))
119 ;
120 }
121 }
122
config_apollo(void)123 void __init config_apollo(void)
124 {
125 int i;
126
127 dn_setup_model();
128
129 mach_sched_init=dn_sched_init; /* */
130 mach_init_IRQ=dn_init_IRQ;
131 mach_hwclk = dn_dummy_hwclk; /* */
132 mach_reset = dn_dummy_reset; /* */
133 #ifdef CONFIG_HEARTBEAT
134 mach_heartbeat = dn_heartbeat;
135 #endif
136 mach_get_model = dn_get_model;
137
138 cpuctrl=0xaa00;
139
140 /* clear DMA translation table */
141 for(i=0;i<0x400;i++)
142 addr_xlat_map[i]=0;
143
144 }
145
dn_timer_int(int irq,void * dev_id)146 irqreturn_t dn_timer_int(int irq, void *dev_id)
147 {
148 unsigned char *at = (unsigned char *)apollo_timer;
149
150 legacy_timer_tick(1);
151 timer_heartbeat();
152
153 READ_ONCE(*(at + 3));
154 READ_ONCE(*(at + 5));
155
156 return IRQ_HANDLED;
157 }
158
dn_sched_init(void)159 void dn_sched_init(void)
160 {
161 /* program timer 1 */
162 *(volatile unsigned char *)(apollo_timer + 3) = 0x01;
163 *(volatile unsigned char *)(apollo_timer + 1) = 0x40;
164 *(volatile unsigned char *)(apollo_timer + 5) = 0x09;
165 *(volatile unsigned char *)(apollo_timer + 7) = 0xc4;
166
167 /* enable IRQ of PIC B */
168 *(volatile unsigned char *)(pica+1)&=(~8);
169
170 #if 0
171 pr_info("*(0x10803) %02x\n",
172 *(volatile unsigned char *)(apollo_timer + 0x3));
173 pr_info("*(0x10803) %02x\n",
174 *(volatile unsigned char *)(apollo_timer + 0x3));
175 #endif
176
177 if (request_irq(IRQ_APOLLO, dn_timer_int, 0, "time", NULL))
178 pr_err("Couldn't register timer interrupt\n");
179 }
180
dn_dummy_hwclk(int op,struct rtc_time * t)181 int dn_dummy_hwclk(int op, struct rtc_time *t) {
182
183
184 if(!op) { /* read */
185 t->tm_sec=rtc->second;
186 t->tm_min=rtc->minute;
187 t->tm_hour=rtc->hours;
188 t->tm_mday=rtc->day_of_month;
189 t->tm_wday=rtc->day_of_week;
190 t->tm_mon = rtc->month - 1;
191 t->tm_year=rtc->year;
192 if (t->tm_year < 70)
193 t->tm_year += 100;
194 } else {
195 rtc->second=t->tm_sec;
196 rtc->minute=t->tm_min;
197 rtc->hours=t->tm_hour;
198 rtc->day_of_month=t->tm_mday;
199 if(t->tm_wday!=-1)
200 rtc->day_of_week=t->tm_wday;
201 rtc->month = t->tm_mon + 1;
202 rtc->year = t->tm_year % 100;
203 }
204
205 return 0;
206
207 }
208
dn_dummy_reset(void)209 static void dn_dummy_reset(void)
210 {
211 dn_serial_print("The end !\n");
212
213 for(;;);
214
215 }
216
dn_get_model(char * model)217 static void dn_get_model(char *model)
218 {
219 strcpy(model, "Apollo ");
220 if (apollo_model >= APOLLO_DN3000 && apollo_model <= APOLLO_DN4500)
221 strcat(model, apollo_models[apollo_model - APOLLO_DN3000]);
222 }
223
224 #ifdef CONFIG_HEARTBEAT
225 static int dn_cpuctrl=0xff00;
226
dn_heartbeat(int on)227 static void dn_heartbeat(int on) {
228
229 if(on) {
230 dn_cpuctrl&=~0x100;
231 cpuctrl=dn_cpuctrl;
232 }
233 else {
234 dn_cpuctrl&=~0x100;
235 dn_cpuctrl|=0x100;
236 cpuctrl=dn_cpuctrl;
237 }
238 }
239 #endif
240
241