clpssoc.c revision 1.3
1/*	$NetBSD: clpssoc.c,v 1.3 2021/08/07 16:18:43 thorpej Exp $	*/
2/*
3 * Copyright (c) 2013 KIYOHARA Takashi
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__KERNEL_RCSID(0, "$NetBSD: clpssoc.c,v 1.3 2021/08/07 16:18:43 thorpej Exp $");
30
31#include "opt_com.h"
32
33#define _INTR_PRIVATE
34
35#include <sys/param.h>
36#include <sys/bus.h>
37#include <sys/device.h>
38#include <sys/errno.h>
39#include <sys/kernel.h>
40#include <sys/systm.h>
41#include <sys/timetc.h>
42#include <sys/types.h>
43
44#include <arm/mainbus/mainbus.h>
45#include <arm/pic/picvar.h>
46
47#include <machine/epoc32.h>
48#include <machine/limits.h>
49
50#include <arm/clps711x/clps711xreg.h>
51#include <arm/clps711x/clpssocvar.h>
52
53#include "locators.h"
54
55
56static int clpssoc_match(device_t, cfdata_t, void *);
57static void clpssoc_attach(device_t parent, device_t self, void *aux);
58
59static int clpssoc_print(void *, const char *);
60static int clpssoc_submatch(device_t, cfdata_t, const int *, void *);
61
62static int clpssoc_find_pending_irqs(void);
63
64static void clpssoc_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
65static void clpssoc_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
66static void clpssoc_pic_establish_irq(struct pic_softc *, struct intrsource *);
67
68#define INTSR	(*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_INTSR)))
69#define INTMR	(*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_INTMR)))
70#define SYSCON	(*((volatile uint32_t *)(ARM7XX_INTRREG_VBASE + PS711X_SYSCON)))
71#define TC1D	(*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_TC1D)))
72#define TC2D	(*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_TC2D)))
73static void clpssoc_initclocks(void);
74static int clpssoc_clockintr(void *);
75static void clpssoc_tc_init(void);
76static u_int clpssoc_get_timecount(struct timecounter *);
77
78static void clpssoc_delay(unsigned int);
79
80CFATTACH_DECL_NEW(clpssoc, 0, clpssoc_match, clpssoc_attach, NULL, NULL);
81
82static const struct {
83	const char *name;
84	int irq[3];
85} clpssoc_periphs[] = {
86	{ "clpsaudio",	{CLPSSOCCF_IRQ_DEFAULT} },
87	{ "clpscom",	{12, 13, 14} },
88	{ "clpskbd",	{CLPSSOCCF_IRQ_DEFAULT} },
89	{ "clpslcd",	{CLPSSOCCF_IRQ_DEFAULT} },
90	{ "clpspm",	{CLPSSOCCF_IRQ_DEFAULT} },
91	{ "clpsrtc",	{10, CLPSSOCCF_IRQ_DEFAULT} },
92};
93
94extern struct bus_space clps711x_bs_tag;
95
96static struct pic_ops clpssoc_picops = {
97	.pic_unblock_irqs = clpssoc_pic_unblock_irqs,
98	.pic_block_irqs = clpssoc_pic_block_irqs,
99	.pic_establish_irq = clpssoc_pic_establish_irq,
100};
101static struct pic_softc clpssoc_pic = {
102	.pic_ops = &clpssoc_picops,
103	.pic_maxsources = 16,
104	.pic_name = "clpssoc",
105};
106
107/* ARGSUSED */
108static int
109clpssoc_match(device_t parent, cfdata_t match, void *aux)
110{
111
112	return 1;
113}
114
115/* ARGSUSED */
116static void
117clpssoc_attach(device_t parent, device_t self, void *aux)
118{
119	struct mainbus_attach_args *maa = aux;
120	struct clpssoc_attach_args aa;
121	bus_space_handle_t ioh;
122	uint32_t sysflg;
123	int i, j;
124
125	if (bus_space_map(&clps711x_bs_tag, maa->mb_iobase, ARM7XX_INTRREG_SIZE,
126								0, &ioh) != 0) {
127		aprint_error_dev(self, "can't map registers\n");
128		return;
129	}
130	sysflg = bus_space_read_4(&clps711x_bs_tag, ioh, PS711X_SYSFLG);
131	aprint_normal(": CL PS-711x rev %d\n", SYSFLG_VERID(sysflg));
132	aprint_naive("\n");
133
134	INTMR = 0;
135
136	pic_add(&clpssoc_pic, 0);
137	soc_find_pending_irqs = clpssoc_find_pending_irqs;
138	soc_initclocks = clpssoc_initclocks;
139	soc_delay = clpssoc_delay;
140
141	for (i = 0; i < __arraycount(clpssoc_periphs); i++) {
142		aa.aa_name = clpssoc_periphs[i].name;
143		aa.aa_iot = &clps711x_bs_tag;
144		aa.aa_ioh = &ioh;
145		for (j = 0; j < __arraycount(clpssoc_periphs[i].irq); j++)
146			aa.aa_irq[j] = clpssoc_periphs[i].irq[j];
147
148		config_found(self, &aa, clpssoc_print,
149		    CFARGS(.submatch = clpssoc_submatch));
150	}
151}
152
153static int
154clpssoc_print(void *aux, const char *pnp)
155{
156	struct clpssoc_attach_args *aa = aux;
157	int i;
158
159	if (pnp)
160		aprint_normal("%s at %s", aa->aa_name, pnp);
161	else
162		if (aa->aa_irq[0] != CLPSSOCCF_IRQ_DEFAULT) {
163			aprint_normal(" irq %d", aa->aa_irq[0]);
164			for (i = 1; i < __arraycount(aa->aa_irq); i++) {
165				if (aa->aa_irq[i] == CLPSSOCCF_IRQ_DEFAULT)
166					break;
167				aprint_normal(",%d", aa->aa_irq[i]);
168			}
169		}
170
171	return UNCONF;
172}
173
174/* ARGSUSED */
175static int
176clpssoc_submatch(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
177{
178	struct clpssoc_attach_args *aa = aux;
179
180	if (strcmp(aa->aa_name, "clpskbd") == 0 &&
181	    strcmp(cf->cf_name + strlen(cf->cf_name) - 3, "kbd") == 0)
182		return config_match(parent, cf, aux);
183
184	if (strcmp(cf->cf_name, aa->aa_name) != 0)
185		return 0;
186	return config_match(parent, cf, aux);
187}
188
189
190static int
191clpssoc_find_pending_irqs(void)
192{
193	uint16_t pending;
194
195	pending = INTSR;
196	pending &= INTMR;
197	if (pending == 0)
198		return 0;
199
200	return pic_mark_pending_sources(&clpssoc_pic, 0, pending);
201}
202
203/* ARGSUSED */
204static void
205clpssoc_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
206			 uint32_t irq_mask)
207{
208
209	INTMR |= irq_mask;
210}
211
212/* ARGSUSED */
213static void
214clpssoc_pic_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
215{
216
217	INTMR &= ~irq_mask;
218}
219
220static void
221clpssoc_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
222{
223	/* Nothing */
224}
225
226static void
227clpssoc_initclocks(void)
228{
229
230	/* set prescale mode to TC1 and free-running mode TC2 */
231	SYSCON |= (SYSCON_TC1M | SYSCON_TC1S | SYSCON_TC2S);
232	TC1D = 512 * 1000 / hz - 1;	/* 512kHz / hz - 1 */
233	intr_establish(IRQ_TC1DI, IPL_CLOCK, 0, clpssoc_clockintr, NULL);
234
235	clpssoc_tc_init();
236}
237
238static int
239clpssoc_clockintr(void *arg)
240{
241
242	*(volatile uint32_t *)(ARM7XX_INTRREG_VBASE + PS711X_TC1EOI) = 1;
243
244	hardclock(arg);
245
246	return 1;
247}
248
249static void
250clpssoc_tc_init(void)
251{
252	static struct timecounter clpssoc_tc = {
253		.tc_get_timecount = clpssoc_get_timecount,
254		.tc_counter_mask = UINT16_MAX,
255		.tc_frequency = 512000,
256		.tc_name = "clpssoc",
257		.tc_quality = 100,
258	};
259
260	tc_init(&clpssoc_tc);
261}
262
263static u_int
264clpssoc_get_timecount(struct timecounter *tc)
265{
266
267	return TC2D ^ UINT16_MAX;	/* It is decremental counter */
268}
269
270static void
271clpssoc_delay(unsigned int us)
272{
273	int prev, now, remaining;
274
275	prev = TC2D & UINT16_MAX;
276	remaining = us * 512 / 1000 + 1;
277
278	while (remaining > 0) {
279		now = TC2D & UINT16_MAX;
280		if (now >= prev)
281			remaining -= (now - prev);
282		else
283			remaining -= (UINT16_MAX - now + prev + 1);
284		prev = now;
285	}
286}
287