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