1*8eb9eddbSthorpej /* $NetBSD: gbus_io.c,v 1.1 2024/03/06 05:33:09 thorpej Exp $ */
2*8eb9eddbSthorpej
3*8eb9eddbSthorpej /*-
4*8eb9eddbSthorpej * Copyright (c) 2024 The NetBSD Foundation, Inc.
5*8eb9eddbSthorpej * All rights reserved.
6*8eb9eddbSthorpej *
7*8eb9eddbSthorpej * This code is derived from software contributed to The NetBSD Foundation
8*8eb9eddbSthorpej * by Jason R. Thorpe.
9*8eb9eddbSthorpej *
10*8eb9eddbSthorpej * Redistribution and use in source and binary forms, with or without
11*8eb9eddbSthorpej * modification, are permitted provided that the following conditions
12*8eb9eddbSthorpej * are met:
13*8eb9eddbSthorpej * 1. Redistributions of source code must retain the above copyright
14*8eb9eddbSthorpej * notice, this list of conditions and the following disclaimer.
15*8eb9eddbSthorpej * 2. Redistributions in binary form must reproduce the above copyright
16*8eb9eddbSthorpej * notice, this list of conditions and the following disclaimer in the
17*8eb9eddbSthorpej * documentation and/or other materials provided with the distribution.
18*8eb9eddbSthorpej *
19*8eb9eddbSthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20*8eb9eddbSthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21*8eb9eddbSthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22*8eb9eddbSthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23*8eb9eddbSthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*8eb9eddbSthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*8eb9eddbSthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*8eb9eddbSthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*8eb9eddbSthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*8eb9eddbSthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*8eb9eddbSthorpej * POSSIBILITY OF SUCH DAMAGE.
30*8eb9eddbSthorpej */
31*8eb9eddbSthorpej
32*8eb9eddbSthorpej /*
33*8eb9eddbSthorpej * Bus space implementation for the Gbus: a general 8-bit bus found
34*8eb9eddbSthorpej * on Laser / TurboLaser CPU modules.
35*8eb9eddbSthorpej */
36*8eb9eddbSthorpej
37*8eb9eddbSthorpej #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
38*8eb9eddbSthorpej
39*8eb9eddbSthorpej __KERNEL_RCSID(0, "$NetBSD: gbus_io.c,v 1.1 2024/03/06 05:33:09 thorpej Exp $");
40*8eb9eddbSthorpej
41*8eb9eddbSthorpej #include <sys/param.h>
42*8eb9eddbSthorpej #include <sys/systm.h>
43*8eb9eddbSthorpej #include <sys/device.h>
44*8eb9eddbSthorpej #include <sys/endian.h>
45*8eb9eddbSthorpej #include <sys/vmem.h>
46*8eb9eddbSthorpej
47*8eb9eddbSthorpej #include <sys/bus.h>
48*8eb9eddbSthorpej
49*8eb9eddbSthorpej #include <alpha/gbus/gbusvar.h>
50*8eb9eddbSthorpej
51*8eb9eddbSthorpej /*
52*8eb9eddbSthorpej * While physically there is one Gbus per CPU module on the system,
53*8eb9eddbSthorpej * logically there is only one (the one on the CPU module that holds
54*8eb9eddbSthorpej * the primary CPU), and this describes it.
55*8eb9eddbSthorpej */
56*8eb9eddbSthorpej static struct gbus_config {
57*8eb9eddbSthorpej paddr_t gc_sysbase; /* system base address of Gbus */
58*8eb9eddbSthorpej struct alpha_bus_space gc_st; /* the Gbus's space tag */
59*8eb9eddbSthorpej } gbus_config;
60*8eb9eddbSthorpej
61*8eb9eddbSthorpej /* Adjacent bytes on the Gbus are spaced 64 bytes apart. */
62*8eb9eddbSthorpej #define GBUS_ADDR_SHIFT 6
63*8eb9eddbSthorpej
64*8eb9eddbSthorpej static int
gbus_io_map(void * v,bus_addr_t addr,bus_size_t size __unused,int flags __unused,bus_space_handle_t * iohp,int acct __unused)65*8eb9eddbSthorpej gbus_io_map(
66*8eb9eddbSthorpej void *v,
67*8eb9eddbSthorpej bus_addr_t addr,
68*8eb9eddbSthorpej bus_size_t size __unused,
69*8eb9eddbSthorpej int flags __unused,
70*8eb9eddbSthorpej bus_space_handle_t *iohp,
71*8eb9eddbSthorpej int acct __unused)
72*8eb9eddbSthorpej {
73*8eb9eddbSthorpej struct gbus_config * const gc = v;
74*8eb9eddbSthorpej
75*8eb9eddbSthorpej *iohp = ALPHA_PHYS_TO_K0SEG(gc->gc_sysbase + addr);
76*8eb9eddbSthorpej
77*8eb9eddbSthorpej return 0;
78*8eb9eddbSthorpej }
79*8eb9eddbSthorpej
80*8eb9eddbSthorpej static void
gbus_io_unmap(void * v __unused,bus_space_handle_t ioh __unused,bus_size_t size __unused,int acct __unused)81*8eb9eddbSthorpej gbus_io_unmap(
82*8eb9eddbSthorpej void *v __unused,
83*8eb9eddbSthorpej bus_space_handle_t ioh __unused,
84*8eb9eddbSthorpej bus_size_t size __unused,
85*8eb9eddbSthorpej int acct __unused)
86*8eb9eddbSthorpej {
87*8eb9eddbSthorpej /* No work to do. */
88*8eb9eddbSthorpej }
89*8eb9eddbSthorpej
90*8eb9eddbSthorpej static void
gbus_io_barrier(void * v __unused,bus_space_handle_t ioh __unused,bus_size_t off __unused,bus_size_t len __unused,int flags __unused)91*8eb9eddbSthorpej gbus_io_barrier(
92*8eb9eddbSthorpej void *v __unused,
93*8eb9eddbSthorpej bus_space_handle_t ioh __unused,
94*8eb9eddbSthorpej bus_size_t off __unused,
95*8eb9eddbSthorpej bus_size_t len __unused,
96*8eb9eddbSthorpej int flags __unused)
97*8eb9eddbSthorpej {
98*8eb9eddbSthorpej if (flags & BUS_SPACE_BARRIER_READ) {
99*8eb9eddbSthorpej alpha_mb();
100*8eb9eddbSthorpej } else if (flags & BUS_SPACE_BARRIER_WRITE) {
101*8eb9eddbSthorpej alpha_wmb();
102*8eb9eddbSthorpej }
103*8eb9eddbSthorpej }
104*8eb9eddbSthorpej
105*8eb9eddbSthorpej __CTASSERT(_BYTE_ORDER == _LITTLE_ENDIAN);
106*8eb9eddbSthorpej
107*8eb9eddbSthorpej /*
108*8eb9eddbSthorpej * A 32-bit pointer is used here because the bus transaction is going to
109*8eb9eddbSthorpej * be 32-bit regardless, and this avoids having the compiler generate
110*8eb9eddbSthorpej * extbl / insbl / mskbl unnecessarily (or r/m/w in the write case).
111*8eb9eddbSthorpej */
112*8eb9eddbSthorpej #define GBUS_ADDR(ioh, off) \
113*8eb9eddbSthorpej (uint32_t *)((ioh) + ((off) << GBUS_ADDR_SHIFT))
114*8eb9eddbSthorpej
115*8eb9eddbSthorpej static uint8_t
gbus_io_read_1(void * v __unused,bus_space_handle_t ioh,bus_size_t off)116*8eb9eddbSthorpej gbus_io_read_1(
117*8eb9eddbSthorpej void *v __unused,
118*8eb9eddbSthorpej bus_space_handle_t ioh,
119*8eb9eddbSthorpej bus_size_t off)
120*8eb9eddbSthorpej {
121*8eb9eddbSthorpej uint32_t *addr = GBUS_ADDR(ioh, off);
122*8eb9eddbSthorpej
123*8eb9eddbSthorpej alpha_mb();
124*8eb9eddbSthorpej return (uint8_t)atomic_load_relaxed(addr);
125*8eb9eddbSthorpej }
126*8eb9eddbSthorpej
127*8eb9eddbSthorpej static void
gbus_io_write_1(void * v __unused,bus_space_handle_t ioh,bus_size_t off,uint8_t val)128*8eb9eddbSthorpej gbus_io_write_1(
129*8eb9eddbSthorpej void *v __unused,
130*8eb9eddbSthorpej bus_space_handle_t ioh,
131*8eb9eddbSthorpej bus_size_t off,
132*8eb9eddbSthorpej uint8_t val)
133*8eb9eddbSthorpej {
134*8eb9eddbSthorpej uint32_t *addr = GBUS_ADDR(ioh, off);
135*8eb9eddbSthorpej
136*8eb9eddbSthorpej atomic_store_relaxed(addr, (uint32_t)val);
137*8eb9eddbSthorpej alpha_mb();
138*8eb9eddbSthorpej }
139*8eb9eddbSthorpej
140*8eb9eddbSthorpej bus_space_tag_t
gbus_io_init(paddr_t sysbase)141*8eb9eddbSthorpej gbus_io_init(paddr_t sysbase)
142*8eb9eddbSthorpej {
143*8eb9eddbSthorpej struct gbus_config * const gc = &gbus_config;
144*8eb9eddbSthorpej bus_space_tag_t t = &gc->gc_st;
145*8eb9eddbSthorpej
146*8eb9eddbSthorpej if (t->abs_cookie == gc) {
147*8eb9eddbSthorpej /* Already initialized. */
148*8eb9eddbSthorpej KASSERT(gc->gc_sysbase == sysbase);
149*8eb9eddbSthorpej return t;
150*8eb9eddbSthorpej }
151*8eb9eddbSthorpej
152*8eb9eddbSthorpej gc->gc_sysbase = sysbase;
153*8eb9eddbSthorpej memset(t, 0, sizeof(*t));
154*8eb9eddbSthorpej
155*8eb9eddbSthorpej /*
156*8eb9eddbSthorpej * Initialize the bus space tag. We just support the bare
157*8eb9eddbSthorpej * minimum operations required by Gbus devices.
158*8eb9eddbSthorpej */
159*8eb9eddbSthorpej
160*8eb9eddbSthorpej /* cookie */
161*8eb9eddbSthorpej t->abs_cookie = gc;
162*8eb9eddbSthorpej
163*8eb9eddbSthorpej /* mapping/unmapping */
164*8eb9eddbSthorpej t->abs_map = gbus_io_map;
165*8eb9eddbSthorpej t->abs_unmap = gbus_io_unmap;
166*8eb9eddbSthorpej
167*8eb9eddbSthorpej /* barrier */
168*8eb9eddbSthorpej t->abs_barrier = gbus_io_barrier;
169*8eb9eddbSthorpej
170*8eb9eddbSthorpej /* read (single) */
171*8eb9eddbSthorpej t->abs_r_1 = gbus_io_read_1;
172*8eb9eddbSthorpej
173*8eb9eddbSthorpej /* write (single) */
174*8eb9eddbSthorpej t->abs_w_1 = gbus_io_write_1;
175*8eb9eddbSthorpej
176*8eb9eddbSthorpej return t;
177*8eb9eddbSthorpej }
178