1 /* $NetBSD: mpc5200_ata.c,v 1.1 2026/06/27 13:28:35 rkujawa Exp $ */ 2 3 /*- 4 * Copyright (c) 2008, 2026 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Radoslaw Kujawa and Robert Swindells. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Driver for the Freescale MPC5200B on-chip ATA Controller, in PIO mode. 34 * 35 * This is a reworking of Robert Swindells' MPC5200 IDE driver (mpc5200_ide.c). 36 * 37 * DMA is deliberately not implemented. The MPC5200B can ONLY reach memory 38 * from the ATA FIFO through the BestComm SDMA engine, and that path is both 39 * documented-broken and widely reported to silently corrupt data when caches 40 * are on. 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: mpc5200_ata.c,v 1.1 2026/06/27 13:28:35 rkujawa Exp $"); 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/device.h> 49 #include <sys/bus.h> 50 51 #include <sys/endian.h> 52 53 #include <machine/intr.h> 54 55 #include <dev/ata/atavar.h> 56 #include <dev/ic/wdcvar.h> 57 58 #include <powerpc/mpc5200/obiovar.h> 59 #include <powerpc/mpc5200/cdmvar.h> 60 #include <powerpc/mpc5200/mpc5200reg.h> 61 #include <powerpc/mpc5200/mpc5200_atareg.h> 62 #include <powerpc/mpc5200/mpc5200_atavar.h> 63 64 /* 65 * The ATA controller's INTRQ is hardwired to SIU peripheral source 7 66 */ 67 #define MPCATA_PERIPH_SOURCE 7 68 #define MPCATA_IRQ (64 + MPCATA_PERIPH_SOURCE) 69 70 /* Highest PIO mode the controller and this driver support. */ 71 #define MPCATA_PIO_MAX 4 72 73 /* 74 * Transceiver propagation delay added to the read-strobe widths (t2_8/t2_16), 75 */ 76 #define MPCATA_XCVR_PROP_NS 10 77 78 static int mpcata_match(device_t, cfdata_t, void *); 79 static void mpcata_attach(device_t, device_t, void *); 80 81 static void mpcata_set_modes(struct ata_channel *); 82 static void mpcata_program_pio(struct mpcata_softc *, int); 83 static void mpcata_datain(struct ata_channel *, int, void *, size_t); 84 static void mpcata_dataout(struct ata_channel *, int, void *, size_t); 85 86 CFATTACH_DECL_NEW(mpcata, sizeof(struct mpcata_softc), 87 mpcata_match, mpcata_attach, NULL, NULL); 88 89 /* 90 * ATA-4 PIO-mode minimum bus timings 91 */ 92 static const struct mpcata_pio_timing { 93 uint16_t t0; /* cycle time */ 94 uint16_t t1; /* address setup to DIOR/DIOW */ 95 uint16_t t2_8; /* 8-bit DIOR/DIOW pulse width */ 96 uint16_t t2_16; /* 16-bit DIOR/DIOW pulse width */ 97 uint16_t t4; /* DIOW data hold */ 98 uint16_t ta; /* IORDY setup */ 99 } mpcata_pio_timing[] = { 100 { 600, 70, 290, 165, 30, 35 }, /* PIO mode 0 */ 101 { 383, 50, 290, 125, 20, 35 }, /* PIO mode 1 */ 102 { 240, 30, 290, 100, 15, 35 }, /* PIO mode 2 */ 103 { 180, 30, 80, 80, 10, 35 }, /* PIO mode 3 */ 104 { 120, 25, 70, 70, 10, 35 }, /* PIO mode 4 */ 105 }; 106 107 static int 108 mpcata_match(device_t parent, cfdata_t cf, void *aux) 109 { 110 struct obio_attach_args *oba = aux; 111 112 if (strcmp(oba->obio_name, "ata") == 0) 113 return 1; 114 115 return 0; 116 } 117 118 static void 119 mpcata_attach(device_t parent, device_t self, void *aux) 120 { 121 struct mpcata_softc *sc = device_private(self); 122 struct obio_attach_args *oba = aux; 123 struct ata_channel *chp = &sc->sc_channel; 124 struct wdc_regs *wdr = &sc->sc_wdc_regs; 125 bus_addr_t addr; 126 bus_size_t size; 127 int irq, ist, i; 128 129 aprint_naive("\n"); 130 aprint_normal(": MPC5200 ATA controller\n"); 131 132 sc->sc_iot = oba->obio_bst; 133 134 /* 135 * Map the whole ATA register block. 136 */ 137 addr = oba->obio_addr != 0 ? oba->obio_addr : 138 (MPC5200_MBAR_DEFAULT + MPC5200_REG_ATA); 139 size = oba->obio_size != 0 ? oba->obio_size : ATA_REG_SIZE; 140 if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) { 141 aprint_error_dev(self, "can't map registers\n"); 142 return; 143 } 144 145 sc->sc_wdcdev.sc_atac.atac_dev = self; 146 sc->sc_wdcdev.regs = wdr; 147 148 /* 149 * Lay out the wdc command/control handles. 150 */ 151 wdr->cmd_iot = wdr->ctl_iot = sc->sc_iot; 152 wdr->cmd_baseioh = sc->sc_ioh; 153 wdr->cmd_ios = size; 154 for (i = 0; i < WDC_NREG; i++) { 155 if (bus_space_subregion(wdr->cmd_iot, sc->sc_ioh, 156 ATA_DRIVE_BASE + i * ATA_DRIVE_STRIDE, 157 (i == 0) ? 2 : 1, &wdr->cmd_iohs[i]) != 0) { 158 aprint_error_dev(self, "can't subregion taskfile\n"); 159 goto fail; 160 } 161 } 162 if (bus_space_subregion(wdr->ctl_iot, sc->sc_ioh, ATA_DRIVE_CTRL, 1, 163 &wdr->ctl_ioh) != 0) { 164 aprint_error_dev(self, "can't subregion control register\n"); 165 goto fail; 166 } 167 wdc_init_shadow_regs(wdr); 168 169 /* Fill in the wdc/channel description. */ 170 sc->sc_wdcdev.sc_atac.atac_cap = ATAC_CAP_DATA16; 171 sc->sc_wdcdev.sc_atac.atac_pio_cap = MPCATA_PIO_MAX; 172 sc->sc_wdcdev.sc_atac.atac_channels = sc->sc_chanarray; 173 sc->sc_wdcdev.sc_atac.atac_nchannels = 1; 174 sc->sc_wdcdev.sc_atac.atac_set_modes = mpcata_set_modes; 175 sc->sc_wdcdev.wdc_maxdrives = 2; 176 /* The 16-bit data register is byte-swapped relative to the host. */ 177 sc->sc_wdcdev.datain_pio = mpcata_datain; 178 sc->sc_wdcdev.dataout_pio = mpcata_dataout; 179 180 sc->sc_chanarray[0] = chp; 181 chp->ch_channel = 0; 182 chp->ch_atac = &sc->sc_wdcdev.sc_atac; 183 184 /* 185 * Bring the host state machine to a known state 186 */ 187 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ATA_CONFIG, 188 ATA_CONFIG_SMR | ATA_CONFIG_FR); 189 delay(10); 190 mpcata_program_pio(sc, 0); 191 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ATA_CONFIG, 192 ATA_CONFIG_IE | ATA_CONFIG_IORDY); 193 /* Clear any latched host read/write error flags (write-1-to-clear). */ 194 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ATA_HOST_STATUS, 195 ATA_HOST_STATUS_RERR | ATA_HOST_STATUS_WERR); 196 197 /* 198 * Establish the drive interrupt. 199 */ 200 if (!obio_decode_interrupt(oba->obio_node, 0, &irq, &ist)) { 201 irq = MPCATA_IRQ; 202 ist = IST_LEVEL; 203 } 204 sc->sc_ih = intr_establish(irq, ist, IPL_BIO, wdcintr, chp); 205 if (sc->sc_ih == NULL) { 206 aprint_error_dev(self, 207 "can't establish irq %d, using polled I/O\n", irq); 208 sc->sc_wdcdev.sc_atac.atac_cap |= ATAC_CAP_NOIRQ; 209 } else { 210 aprint_normal_dev(self, "interrupting at irq %d\n", irq); 211 } 212 213 wdcattach(chp); 214 return; 215 216 fail: 217 bus_space_unmap(sc->sc_iot, sc->sc_ioh, size); 218 } 219 220 static uint8_t 221 mpcata_ns_to_count(uint32_t ns, uint32_t ipb_hz, uint32_t extra_ns) 222 { 223 uint64_t period_ps = 1000000000000ULL / ipb_hz; 224 uint64_t spec_ps = (uint64_t)(ns + extra_ns) * 1000; 225 uint64_t count = (spec_ps + period_ps - 1) / period_ps; 226 227 if (count > 255) 228 count = 255; 229 return (uint8_t)count; 230 } 231 232 /* 233 * Program the host PIO timing registers for the given mode. 234 */ 235 static void 236 mpcata_program_pio(struct mpcata_softc *sc, int mode) 237 { 238 const struct mpcata_pio_timing *t; 239 uint32_t ipb, pio1, pio2; 240 uint8_t t0, t1, t2_8, t2_16, t4, ta; 241 242 if (mode < 0 || mode > MPCATA_PIO_MAX) 243 mode = 0; 244 t = &mpcata_pio_timing[mode]; 245 ipb = mpc5200_cdm_get_ipb_freq(); /* never returns zero */ 246 247 t0 = mpcata_ns_to_count(t->t0, ipb, 0); 248 t1 = mpcata_ns_to_count(t->t1, ipb, 0); 249 t2_8 = mpcata_ns_to_count(t->t2_8, ipb, 2 * MPCATA_XCVR_PROP_NS); 250 t2_16 = mpcata_ns_to_count(t->t2_16, ipb, 2 * MPCATA_XCVR_PROP_NS); 251 t4 = mpcata_ns_to_count(t->t4, ipb, 0); 252 ta = mpcata_ns_to_count(t->ta, ipb, 0); 253 254 pio1 = ((uint32_t)t0 << 24) | ((uint32_t)t2_8 << 16) | 255 ((uint32_t)t2_16 << 8); 256 pio2 = ((uint32_t)t4 << 24) | ((uint32_t)t1 << 16) | 257 ((uint32_t)ta << 8); 258 259 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ATA_PIO1, pio1); 260 bus_space_write_4(sc->sc_iot, sc->sc_ioh, ATA_PIO2, pio2); 261 sc->sc_pio_mode = mode; 262 } 263 264 static void 265 mpcata_set_modes(struct ata_channel *chp) 266 { 267 struct mpcata_softc *sc = (struct mpcata_softc *)chp->ch_atac; 268 int drive, mode = MPCATA_PIO_MAX; 269 270 for (drive = 0; drive < sc->sc_wdcdev.wdc_maxdrives; drive++) { 271 struct ata_drive_datas *drvp = &chp->ch_drive[drive]; 272 273 if (drvp->drive_type == ATA_DRIVET_NONE) 274 continue; 275 if (drvp->PIO_mode < mode) 276 mode = drvp->PIO_mode; 277 } 278 279 mpcata_program_pio(sc, mode); 280 281 for (drive = 0; drive < sc->sc_wdcdev.wdc_maxdrives; drive++) { 282 struct ata_drive_datas *drvp = &chp->ch_drive[drive]; 283 284 if (drvp->drive_type == ATA_DRIVET_NONE) 285 continue; 286 drvp->PIO_mode = sc->sc_pio_mode; 287 drvp->drive_flags &= ~(ATA_DRIVE_DMA | ATA_DRIVE_UDMA); 288 } 289 } 290 291 /* 292 * Surely this can be done in a more elegant way, but the controller is slow enough 293 * that it doesn't matter. 294 */ 295 static void 296 mpcata_datain(struct ata_channel *chp, int flags, void *bf, size_t len) 297 { 298 struct wdc_regs *wdr = CHAN_TO_WDC_REGS(chp); 299 uint16_t *p = bf; 300 301 while (len >= sizeof(*p)) { 302 *p++ = htole16(bus_space_read_2(wdr->cmd_iot, 303 wdr->cmd_iohs[wd_data], 0)); 304 len -= sizeof(*p); 305 } 306 } 307 308 static void 309 mpcata_dataout(struct ata_channel *chp, int flags, void *bf, size_t len) 310 { 311 struct wdc_regs *wdr = CHAN_TO_WDC_REGS(chp); 312 uint16_t *p = bf; 313 314 while (len >= sizeof(*p)) { 315 bus_space_write_2(wdr->cmd_iot, wdr->cmd_iohs[wd_data], 0, 316 le16toh(*p++)); 317 len -= sizeof(*p); 318 } 319 } 320 321