Home | History | Annotate | Line # | Download | only in dev
hollywood.c revision 1.3
      1 /* $NetBSD: hollywood.c,v 1.3 2024/09/22 13:56:25 jmcneill Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2024 Jared McNeill <jmcneill (at) invisible.ca>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 __KERNEL_RCSID(0, "$NetBSD: hollywood.c,v 1.3 2024/09/22 13:56:25 jmcneill Exp $");
     31 
     32 #include <sys/param.h>
     33 #include <sys/bus.h>
     34 #include <sys/device.h>
     35 #include <sys/systm.h>
     36 #include <sys/bitops.h>
     37 
     38 #include <machine/intr.h>
     39 #include <machine/wii.h>
     40 #include <machine/pio.h>
     41 #include <powerpc/pic/picvar.h>
     42 
     43 #include "locators.h"
     44 #include "mainbus.h"
     45 #include "hollywood.h"
     46 
     47 #define WR4(reg, val)		out32(reg, val)
     48 #define RD4(reg)		in32(reg)
     49 
     50 static struct mainbus_attach_args hollywood_maa;
     51 static uint32_t pic_irqmask;
     52 
     53 static int	hollywood_match(device_t, cfdata_t, void *);
     54 static void	hollywood_attach(device_t, device_t, void *);
     55 
     56 static int	hollywood_search(device_t, cfdata_t, const int *, void *);
     57 static int	hollywood_print(void *, const char *);
     58 
     59 static void	hollywood_intr_init(int);
     60 static void	hollywood_enable_irq(struct pic_ops *, int, int);
     61 static void	hollywood_disable_irq(struct pic_ops *, int);
     62 static int	hollywood_get_irq(struct pic_ops *, int);
     63 static void	hollywood_ack_irq(struct pic_ops *, int);
     64 static void	hollywood_establish_irq(struct pic_ops *, int, int, int);
     65 
     66 static struct pic_ops hollywood_pic = {
     67 	.pic_name = "hollywood",
     68 	.pic_numintrs = 32,
     69 	.pic_cookie = NULL,
     70 	.pic_enable_irq = hollywood_enable_irq,
     71 	.pic_reenable_irq = hollywood_enable_irq,
     72 	.pic_disable_irq = hollywood_disable_irq,
     73 	.pic_get_irq = hollywood_get_irq,
     74 	.pic_ack_irq = hollywood_ack_irq,
     75 	.pic_establish_irq = hollywood_establish_irq,
     76 };
     77 
     78 CFATTACH_DECL_NEW(hollywood, 0,
     79 	hollywood_match, hollywood_attach, NULL, NULL);
     80 
     81 static int
     82 hollywood_match(device_t parent, cfdata_t cf, void *aux)
     83 {
     84 	struct mainbus_attach_args *maa = aux;
     85 
     86 	return strcmp(maa->maa_name, "hollywood") == 0;
     87 }
     88 
     89 static void
     90 hollywood_attach(device_t parent, device_t self, void *aux)
     91 {
     92 	uint32_t val;
     93 
     94 	hollywood_maa = *(struct mainbus_attach_args *)aux;
     95 
     96 	val = RD4(HW_VERSION);
     97 
     98 	aprint_naive("\n");
     99 	aprint_normal(": Hollywood ES%u.%u\n",
    100 	    (unsigned)__SHIFTOUT(val, HWVER_MASK) + 1,
    101 	    (unsigned)__SHIFTOUT(val, HWREV_MASK));
    102 
    103 	hollywood_intr_init(hollywood_maa.maa_irq);
    104 
    105 	config_search(self, NULL,
    106 	    CFARGS(.search = hollywood_search));
    107 }
    108 
    109 static int
    110 hollywood_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
    111 {
    112 	struct hollywood_attach_args haa;
    113 
    114 	haa.haa_bst = hollywood_maa.maa_bst;
    115 	haa.haa_dmat = hollywood_maa.maa_dmat;
    116 	if (cf->cf_loc[HOLLYWOODCF_ADDR] != HOLLYWOODCF_ADDR_DEFAULT) {
    117 		haa.haa_addr = cf->cf_loc[HOLLYWOODCF_ADDR];
    118 	} else {
    119 		haa.haa_addr = 0;
    120 	}
    121 	haa.haa_irq = cf->cf_loc[HOLLYWOODCF_IRQ];
    122 
    123 	if (config_probe(parent, cf, &haa)) {
    124 		config_attach(parent, cf, &haa, hollywood_print,
    125 		    CFARGS_NONE);
    126 	}
    127 
    128 	return 0;
    129 }
    130 
    131 static int
    132 hollywood_print(void *aux, const char *pnp)
    133 {
    134 	struct hollywood_attach_args *haa = aux;
    135 
    136 	if (pnp != NULL) {
    137 		return QUIET;
    138 	}
    139 
    140 	if (haa->haa_addr != 0) {
    141 		aprint_normal(" addr 0x%lx", haa->haa_addr);
    142 	}
    143 	if (haa->haa_irq != HOLLYWOODCF_IRQ_DEFAULT) {
    144 		aprint_normal(" irq %d", haa->haa_irq);
    145 	}
    146 
    147 	return UNCONF;
    148 }
    149 
    150 static void
    151 hollywood_enable_irq(struct pic_ops *pic, int irq, int type)
    152 {
    153 	pic_irqmask |= __BIT(irq);
    154 	WR4(HW_PPCIRQMASK, pic_irqmask);
    155 }
    156 
    157 static void
    158 hollywood_disable_irq(struct pic_ops *pic, int irq)
    159 {
    160 	pic_irqmask &= ~__BIT(irq);
    161 	WR4(HW_PPCIRQMASK, pic_irqmask);
    162 }
    163 
    164 static int
    165 hollywood_get_irq(struct pic_ops *pic, int mode)
    166 {
    167 	uint32_t raw, pend;
    168 	int irq;
    169 
    170 	raw = RD4(HW_PPCIRQFLAGS);
    171 	pend = raw & pic_irqmask;
    172 	if (pend == 0) {
    173 		return 255;
    174 	}
    175 	irq = ffs32(pend) - 1;
    176 
    177 	return irq;
    178 }
    179 
    180 static void
    181 hollywood_ack_irq(struct pic_ops *pic, int irq)
    182 {
    183 	WR4(HW_PPCIRQFLAGS, __BIT(irq));
    184 }
    185 
    186 static void
    187 hollywood_establish_irq(struct pic_ops *pic, int irq, int type, int pri)
    188 {
    189 	uint32_t val;
    190 
    191 	/* Mask and clear Starlet interrupt */
    192 	val = RD4(HW_ARMIRQMASK);
    193 	val &= ~__BIT(irq);
    194 	WR4(HW_ARMIRQMASK, val);
    195 	WR4(HW_ARMIRQFLAGS, __BIT(irq));
    196 }
    197 
    198 static void
    199 hollywood_intr_init(int irq)
    200 {
    201 	pic_irqmask = 0;
    202 
    203 	/* Mask and clear all interrupts. */
    204 	WR4(HW_PPCIRQMASK, 0);
    205 	WR4(HW_PPCIRQFLAGS, ~0U);
    206 
    207 	pic_add(&hollywood_pic);
    208 
    209 	intr_establish_xname(irq, IST_LEVEL, IPL_SCHED, pic_handle_intr,
    210 	    &hollywood_pic, "hollywood0");
    211 }
    212 
    213 void *
    214 hollywood_intr_establish(int irq, int ipl, int (*func)(void *), void *arg,
    215     const char *name)
    216 {
    217 	KASSERT(hollywood_pic.pic_intrbase != 0);
    218 
    219 	return intr_establish_xname(hollywood_pic.pic_intrbase + irq,
    220 	    IST_LEVEL, ipl, func, arg, name);
    221 }
    222 
    223 void
    224 hollywood_claim_device(device_t dev, uint32_t mask)
    225 {
    226 	/* Restrict IOP access to a device, giving exclusive access to PPC. */
    227 	WR4(HW_AHBPROT, RD4(HW_AHBPROT) & ~mask);
    228 }
    229