clpssoc.c revision 1.3
11.3Sthorpej/*	$NetBSD: clpssoc.c,v 1.3 2021/08/07 16:18:43 thorpej Exp $	*/
21.1Skiyohara/*
31.1Skiyohara * Copyright (c) 2013 KIYOHARA Takashi
41.1Skiyohara * All rights reserved.
51.1Skiyohara *
61.1Skiyohara * Redistribution and use in source and binary forms, with or without
71.1Skiyohara * modification, are permitted provided that the following conditions
81.1Skiyohara * are met:
91.1Skiyohara * 1. Redistributions of source code must retain the above copyright
101.1Skiyohara *    notice, this list of conditions and the following disclaimer.
111.1Skiyohara * 2. Redistributions in binary form must reproduce the above copyright
121.1Skiyohara *    notice, this list of conditions and the following disclaimer in the
131.1Skiyohara *    documentation and/or other materials provided with the distribution.
141.1Skiyohara *
151.1Skiyohara * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
161.1Skiyohara * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
171.1Skiyohara * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
181.1Skiyohara * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
191.1Skiyohara * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
201.1Skiyohara * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
211.1Skiyohara * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
221.1Skiyohara * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
231.1Skiyohara * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
241.1Skiyohara * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
251.1Skiyohara * POSSIBILITY OF SUCH DAMAGE.
261.1Skiyohara */
271.1Skiyohara
281.1Skiyohara#include <sys/cdefs.h>
291.3Sthorpej__KERNEL_RCSID(0, "$NetBSD: clpssoc.c,v 1.3 2021/08/07 16:18:43 thorpej Exp $");
301.1Skiyohara
311.1Skiyohara#include "opt_com.h"
321.1Skiyohara
331.1Skiyohara#define _INTR_PRIVATE
341.1Skiyohara
351.1Skiyohara#include <sys/param.h>
361.1Skiyohara#include <sys/bus.h>
371.1Skiyohara#include <sys/device.h>
381.1Skiyohara#include <sys/errno.h>
391.1Skiyohara#include <sys/kernel.h>
401.1Skiyohara#include <sys/systm.h>
411.1Skiyohara#include <sys/timetc.h>
421.1Skiyohara#include <sys/types.h>
431.1Skiyohara
441.1Skiyohara#include <arm/mainbus/mainbus.h>
451.1Skiyohara#include <arm/pic/picvar.h>
461.1Skiyohara
471.1Skiyohara#include <machine/epoc32.h>
481.1Skiyohara#include <machine/limits.h>
491.1Skiyohara
501.1Skiyohara#include <arm/clps711x/clps711xreg.h>
511.1Skiyohara#include <arm/clps711x/clpssocvar.h>
521.1Skiyohara
531.1Skiyohara#include "locators.h"
541.1Skiyohara
551.1Skiyohara
561.1Skiyoharastatic int clpssoc_match(device_t, cfdata_t, void *);
571.1Skiyoharastatic void clpssoc_attach(device_t parent, device_t self, void *aux);
581.1Skiyohara
591.1Skiyoharastatic int clpssoc_print(void *, const char *);
601.1Skiyoharastatic int clpssoc_submatch(device_t, cfdata_t, const int *, void *);
611.1Skiyohara
621.1Skiyoharastatic int clpssoc_find_pending_irqs(void);
631.1Skiyohara
641.1Skiyoharastatic void clpssoc_pic_unblock_irqs(struct pic_softc *, size_t, uint32_t);
651.1Skiyoharastatic void clpssoc_pic_block_irqs(struct pic_softc *, size_t, uint32_t);
661.1Skiyoharastatic void clpssoc_pic_establish_irq(struct pic_softc *, struct intrsource *);
671.1Skiyohara
681.1Skiyohara#define INTSR	(*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_INTSR)))
691.1Skiyohara#define INTMR	(*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_INTMR)))
701.1Skiyohara#define SYSCON	(*((volatile uint32_t *)(ARM7XX_INTRREG_VBASE + PS711X_SYSCON)))
711.1Skiyohara#define TC1D	(*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_TC1D)))
721.1Skiyohara#define TC2D	(*((volatile uint16_t *)(ARM7XX_INTRREG_VBASE + PS711X_TC2D)))
731.1Skiyoharastatic void clpssoc_initclocks(void);
741.1Skiyoharastatic int clpssoc_clockintr(void *);
751.1Skiyoharastatic void clpssoc_tc_init(void);
761.1Skiyoharastatic u_int clpssoc_get_timecount(struct timecounter *);
771.1Skiyohara
781.1Skiyoharastatic void clpssoc_delay(unsigned int);
791.1Skiyohara
801.1SkiyoharaCFATTACH_DECL_NEW(clpssoc, 0, clpssoc_match, clpssoc_attach, NULL, NULL);
811.1Skiyohara
821.1Skiyoharastatic const struct {
831.1Skiyohara	const char *name;
841.1Skiyohara	int irq[3];
851.1Skiyohara} clpssoc_periphs[] = {
861.1Skiyohara	{ "clpsaudio",	{CLPSSOCCF_IRQ_DEFAULT} },
871.1Skiyohara	{ "clpscom",	{12, 13, 14} },
881.1Skiyohara	{ "clpskbd",	{CLPSSOCCF_IRQ_DEFAULT} },
891.1Skiyohara	{ "clpslcd",	{CLPSSOCCF_IRQ_DEFAULT} },
901.1Skiyohara	{ "clpspm",	{CLPSSOCCF_IRQ_DEFAULT} },
911.1Skiyohara	{ "clpsrtc",	{10, CLPSSOCCF_IRQ_DEFAULT} },
921.1Skiyohara};
931.1Skiyohara
941.1Skiyoharaextern struct bus_space clps711x_bs_tag;
951.1Skiyohara
961.1Skiyoharastatic struct pic_ops clpssoc_picops = {
971.1Skiyohara	.pic_unblock_irqs = clpssoc_pic_unblock_irqs,
981.1Skiyohara	.pic_block_irqs = clpssoc_pic_block_irqs,
991.1Skiyohara	.pic_establish_irq = clpssoc_pic_establish_irq,
1001.1Skiyohara};
1011.1Skiyoharastatic struct pic_softc clpssoc_pic = {
1021.1Skiyohara	.pic_ops = &clpssoc_picops,
1031.1Skiyohara	.pic_maxsources = 16,
1041.1Skiyohara	.pic_name = "clpssoc",
1051.1Skiyohara};
1061.1Skiyohara
1071.1Skiyohara/* ARGSUSED */
1081.1Skiyoharastatic int
1091.1Skiyoharaclpssoc_match(device_t parent, cfdata_t match, void *aux)
1101.1Skiyohara{
1111.1Skiyohara
1121.1Skiyohara	return 1;
1131.1Skiyohara}
1141.1Skiyohara
1151.1Skiyohara/* ARGSUSED */
1161.1Skiyoharastatic void
1171.1Skiyoharaclpssoc_attach(device_t parent, device_t self, void *aux)
1181.1Skiyohara{
1191.1Skiyohara	struct mainbus_attach_args *maa = aux;
1201.1Skiyohara	struct clpssoc_attach_args aa;
1211.1Skiyohara	bus_space_handle_t ioh;
1221.1Skiyohara	uint32_t sysflg;
1231.1Skiyohara	int i, j;
1241.1Skiyohara
1251.1Skiyohara	if (bus_space_map(&clps711x_bs_tag, maa->mb_iobase, ARM7XX_INTRREG_SIZE,
1261.1Skiyohara								0, &ioh) != 0) {
1271.1Skiyohara		aprint_error_dev(self, "can't map registers\n");
1281.1Skiyohara		return;
1291.1Skiyohara	}
1301.1Skiyohara	sysflg = bus_space_read_4(&clps711x_bs_tag, ioh, PS711X_SYSFLG);
1311.1Skiyohara	aprint_normal(": CL PS-711x rev %d\n", SYSFLG_VERID(sysflg));
1321.1Skiyohara	aprint_naive("\n");
1331.1Skiyohara
1341.1Skiyohara	INTMR = 0;
1351.1Skiyohara
1361.1Skiyohara	pic_add(&clpssoc_pic, 0);
1371.1Skiyohara	soc_find_pending_irqs = clpssoc_find_pending_irqs;
1381.1Skiyohara	soc_initclocks = clpssoc_initclocks;
1391.1Skiyohara	soc_delay = clpssoc_delay;
1401.1Skiyohara
1411.1Skiyohara	for (i = 0; i < __arraycount(clpssoc_periphs); i++) {
1421.1Skiyohara		aa.aa_name = clpssoc_periphs[i].name;
1431.1Skiyohara		aa.aa_iot = &clps711x_bs_tag;
1441.1Skiyohara		aa.aa_ioh = &ioh;
1451.1Skiyohara		for (j = 0; j < __arraycount(clpssoc_periphs[i].irq); j++)
1461.1Skiyohara			aa.aa_irq[j] = clpssoc_periphs[i].irq[j];
1471.1Skiyohara
1481.2Sthorpej		config_found(self, &aa, clpssoc_print,
1491.3Sthorpej		    CFARGS(.submatch = clpssoc_submatch));
1501.1Skiyohara	}
1511.1Skiyohara}
1521.1Skiyohara
1531.1Skiyoharastatic int
1541.1Skiyoharaclpssoc_print(void *aux, const char *pnp)
1551.1Skiyohara{
1561.1Skiyohara	struct clpssoc_attach_args *aa = aux;
1571.1Skiyohara	int i;
1581.1Skiyohara
1591.1Skiyohara	if (pnp)
1601.1Skiyohara		aprint_normal("%s at %s", aa->aa_name, pnp);
1611.1Skiyohara	else
1621.1Skiyohara		if (aa->aa_irq[0] != CLPSSOCCF_IRQ_DEFAULT) {
1631.1Skiyohara			aprint_normal(" irq %d", aa->aa_irq[0]);
1641.1Skiyohara			for (i = 1; i < __arraycount(aa->aa_irq); i++) {
1651.1Skiyohara				if (aa->aa_irq[i] == CLPSSOCCF_IRQ_DEFAULT)
1661.1Skiyohara					break;
1671.1Skiyohara				aprint_normal(",%d", aa->aa_irq[i]);
1681.1Skiyohara			}
1691.1Skiyohara		}
1701.1Skiyohara
1711.1Skiyohara	return UNCONF;
1721.1Skiyohara}
1731.1Skiyohara
1741.1Skiyohara/* ARGSUSED */
1751.1Skiyoharastatic int
1761.1Skiyoharaclpssoc_submatch(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
1771.1Skiyohara{
1781.1Skiyohara	struct clpssoc_attach_args *aa = aux;
1791.1Skiyohara
1801.1Skiyohara	if (strcmp(aa->aa_name, "clpskbd") == 0 &&
1811.1Skiyohara	    strcmp(cf->cf_name + strlen(cf->cf_name) - 3, "kbd") == 0)
1821.1Skiyohara		return config_match(parent, cf, aux);
1831.1Skiyohara
1841.1Skiyohara	if (strcmp(cf->cf_name, aa->aa_name) != 0)
1851.1Skiyohara		return 0;
1861.1Skiyohara	return config_match(parent, cf, aux);
1871.1Skiyohara}
1881.1Skiyohara
1891.1Skiyohara
1901.1Skiyoharastatic int
1911.1Skiyoharaclpssoc_find_pending_irqs(void)
1921.1Skiyohara{
1931.1Skiyohara	uint16_t pending;
1941.1Skiyohara
1951.1Skiyohara	pending = INTSR;
1961.1Skiyohara	pending &= INTMR;
1971.1Skiyohara	if (pending == 0)
1981.1Skiyohara		return 0;
1991.1Skiyohara
2001.1Skiyohara	return pic_mark_pending_sources(&clpssoc_pic, 0, pending);
2011.1Skiyohara}
2021.1Skiyohara
2031.1Skiyohara/* ARGSUSED */
2041.1Skiyoharastatic void
2051.1Skiyoharaclpssoc_pic_unblock_irqs(struct pic_softc *pic, size_t irqbase,
2061.1Skiyohara			 uint32_t irq_mask)
2071.1Skiyohara{
2081.1Skiyohara
2091.1Skiyohara	INTMR |= irq_mask;
2101.1Skiyohara}
2111.1Skiyohara
2121.1Skiyohara/* ARGSUSED */
2131.1Skiyoharastatic void
2141.1Skiyoharaclpssoc_pic_block_irqs(struct pic_softc *pic, size_t irqbase, uint32_t irq_mask)
2151.1Skiyohara{
2161.1Skiyohara
2171.1Skiyohara	INTMR &= ~irq_mask;
2181.1Skiyohara}
2191.1Skiyohara
2201.1Skiyoharastatic void
2211.1Skiyoharaclpssoc_pic_establish_irq(struct pic_softc *pic, struct intrsource *is)
2221.1Skiyohara{
2231.1Skiyohara	/* Nothing */
2241.1Skiyohara}
2251.1Skiyohara
2261.1Skiyoharastatic void
2271.1Skiyoharaclpssoc_initclocks(void)
2281.1Skiyohara{
2291.1Skiyohara
2301.1Skiyohara	/* set prescale mode to TC1 and free-running mode TC2 */
2311.1Skiyohara	SYSCON |= (SYSCON_TC1M | SYSCON_TC1S | SYSCON_TC2S);
2321.1Skiyohara	TC1D = 512 * 1000 / hz - 1;	/* 512kHz / hz - 1 */
2331.1Skiyohara	intr_establish(IRQ_TC1DI, IPL_CLOCK, 0, clpssoc_clockintr, NULL);
2341.1Skiyohara
2351.1Skiyohara	clpssoc_tc_init();
2361.1Skiyohara}
2371.1Skiyohara
2381.1Skiyoharastatic int
2391.1Skiyoharaclpssoc_clockintr(void *arg)
2401.1Skiyohara{
2411.1Skiyohara
2421.1Skiyohara	*(volatile uint32_t *)(ARM7XX_INTRREG_VBASE + PS711X_TC1EOI) = 1;
2431.1Skiyohara
2441.1Skiyohara	hardclock(arg);
2451.1Skiyohara
2461.1Skiyohara	return 1;
2471.1Skiyohara}
2481.1Skiyohara
2491.1Skiyoharastatic void
2501.1Skiyoharaclpssoc_tc_init(void)
2511.1Skiyohara{
2521.1Skiyohara	static struct timecounter clpssoc_tc = {
2531.1Skiyohara		.tc_get_timecount = clpssoc_get_timecount,
2541.1Skiyohara		.tc_counter_mask = UINT16_MAX,
2551.1Skiyohara		.tc_frequency = 512000,
2561.1Skiyohara		.tc_name = "clpssoc",
2571.1Skiyohara		.tc_quality = 100,
2581.1Skiyohara	};
2591.1Skiyohara
2601.1Skiyohara	tc_init(&clpssoc_tc);
2611.1Skiyohara}
2621.1Skiyohara
2631.1Skiyoharastatic u_int
2641.1Skiyoharaclpssoc_get_timecount(struct timecounter *tc)
2651.1Skiyohara{
2661.1Skiyohara
2671.1Skiyohara	return TC2D ^ UINT16_MAX;	/* It is decremental counter */
2681.1Skiyohara}
2691.1Skiyohara
2701.1Skiyoharastatic void
2711.1Skiyoharaclpssoc_delay(unsigned int us)
2721.1Skiyohara{
2731.1Skiyohara	int prev, now, remaining;
2741.1Skiyohara
2751.1Skiyohara	prev = TC2D & UINT16_MAX;
2761.1Skiyohara	remaining = us * 512 / 1000 + 1;
2771.1Skiyohara
2781.1Skiyohara	while (remaining > 0) {
2791.1Skiyohara		now = TC2D & UINT16_MAX;
2801.1Skiyohara		if (now >= prev)
2811.1Skiyohara			remaining -= (now - prev);
2821.1Skiyohara		else
2831.1Skiyohara			remaining -= (UINT16_MAX - now + prev + 1);
2841.1Skiyohara		prev = now;
2851.1Skiyohara	}
2861.1Skiyohara}
287