1 /* $OpenBSD: octsctl.c,v 1.2 2019/01/12 13:50:52 visa Exp $ */
2
3 /*
4 * Copyright (c) 2017 Visa Hankala
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * Driver for OCTEON SATA controller bridge.
21 */
22
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26
27 #include <machine/bus.h>
28 #include <machine/fdt.h>
29
30 #include <dev/ofw/fdt.h>
31 #include <dev/ofw/openfirm.h>
32
33 #define SCTL_SHIM_CFG 0xe8
34 #define SCTL_SHIM_CFG_READ_CMD 0x0000000000001000ul
35 #define SCTL_SHIM_CFG_DMA_BYTE_SWAP 0x0000000000000300ul
36 #define SCTL_SHIM_CFG_DMA_BYTE_SWAP_SHIFT 8
37 #define SCTL_SHIM_CFG_CSR_BYTE_SWAP 0x0000000000000003ul
38 #define SCTL_SHIM_CFG_CSR_BYTE_SWAP_SHIFT 0
39
40 struct octsctl_softc {
41 struct device sc_dev;
42 bus_space_tag_t sc_iot;
43 bus_space_handle_t sc_ioh;
44 };
45
46 int octsctl_match(struct device *, void *, void *);
47 void octsctl_attach(struct device *, struct device *, void *);
48
49 const struct cfattach octsctl_ca = {
50 sizeof(struct octsctl_softc), octsctl_match, octsctl_attach
51 };
52
53 struct cfdriver octsctl_cd = {
54 NULL, "octsctl", DV_DULL
55 };
56
57 int
octsctl_match(struct device * parent,void * match,void * aux)58 octsctl_match(struct device *parent, void *match, void *aux)
59 {
60 struct fdt_attach_args *faa = aux;
61
62 return OF_is_compatible(faa->fa_node, "cavium,octeon-7130-sata-uctl");
63 }
64
65 void
octsctl_attach(struct device * parent,struct device * self,void * aux)66 octsctl_attach(struct device *parent, struct device *self, void *aux)
67 {
68 struct fdt_reg child_reg;
69 struct fdt_attach_args child_faa;
70 struct fdt_attach_args *faa = aux;
71 struct octsctl_softc *sc = (struct octsctl_softc *)self;
72 uint64_t val;
73 uint32_t reg[4];
74 int child;
75
76 child = OF_child(faa->fa_node);
77
78 /*
79 * On some machines, the bridge controller node does not have
80 * an AHCI controller node as a child.
81 */
82 if (child == 0) {
83 printf(": disabled\n");
84 return;
85 }
86
87 if (faa->fa_nreg != 1) {
88 printf(": expected one IO space, got %d\n", faa->fa_nreg);
89 return;
90 }
91
92 if (OF_getpropint(faa->fa_node, "#address-cells", 0) != 2 ||
93 OF_getpropint(faa->fa_node, "#size-cells", 0) != 2) {
94 printf(": invalid fdt reg cells\n");
95 return;
96 }
97 if (OF_getproplen(child, "reg") != sizeof(reg)) {
98 printf(": invalid child fdt reg\n");
99 return;
100 }
101 OF_getpropintarray(child, "reg", reg, sizeof(reg));
102 child_reg.addr = ((uint64_t)reg[0] << 32) | reg[1];
103 child_reg.size = ((uint64_t)reg[2] << 32) | reg[3];
104
105 sc->sc_iot = faa->fa_iot;
106 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, faa->fa_reg[0].size,
107 0, &sc->sc_ioh)) {
108 printf(": could not map registers\n");
109 goto error;
110 }
111
112 val = bus_space_read_8(sc->sc_iot, sc->sc_ioh, SCTL_SHIM_CFG);
113 val &= ~SCTL_SHIM_CFG_CSR_BYTE_SWAP;
114 val &= ~SCTL_SHIM_CFG_DMA_BYTE_SWAP;
115 val |= 3ul << SCTL_SHIM_CFG_CSR_BYTE_SWAP_SHIFT;
116 val |= 1ul << SCTL_SHIM_CFG_DMA_BYTE_SWAP_SHIFT;
117 val |= SCTL_SHIM_CFG_READ_CMD;
118 bus_space_write_8(sc->sc_iot, sc->sc_ioh, SCTL_SHIM_CFG, val);
119 (void)bus_space_read_8(sc->sc_iot, sc->sc_ioh, SCTL_SHIM_CFG);
120
121 printf("\n");
122
123 memset(&child_faa, 0, sizeof(child_faa));
124 child_faa.fa_name = "";
125 child_faa.fa_node = child;
126 child_faa.fa_iot = faa->fa_iot;
127 child_faa.fa_dmat = faa->fa_dmat;
128 child_faa.fa_reg = &child_reg;
129 child_faa.fa_nreg = 1;
130 /* child_faa.fa_intr is not utilized. */
131
132 config_found(self, &child_faa, NULL);
133
134 return;
135
136 error:
137 if (sc->sc_ioh != 0)
138 bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
139 }
140