1*a8b58197Sjsg /* $OpenBSD: amdcf.c,v 1.10 2024/05/20 23:13:33 jsg Exp $ */
26920b493Spirofti
36920b493Spirofti /*
46920b493Spirofti * Copyright (c) 2007, Juniper Networks, Inc.
56920b493Spirofti * All rights reserved.
66920b493Spirofti *
76920b493Spirofti * Redistribution and use in source and binary forms, with or without
86920b493Spirofti * modification, are permitted provided that the following conditions
96920b493Spirofti * are met:
106920b493Spirofti * 1. Redistributions of source code must retain the above copyright
116920b493Spirofti * notice, this list of conditions and the following disclaimer.
126920b493Spirofti * 2. Redistributions in binary form must reproduce the above copyright
136920b493Spirofti * notice, this list of conditions and the following disclaimer in the
146920b493Spirofti * documentation and/or other materials provided with the distribution.
156920b493Spirofti * 3. Neither the name of the author nor the names of any co-contributors
166920b493Spirofti * may be used to endorse or promote products derived from this software
176920b493Spirofti * without specific prior written permission.
186920b493Spirofti *
196920b493Spirofti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
206920b493Spirofti * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
216920b493Spirofti * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
226920b493Spirofti * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
236920b493Spirofti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
246920b493Spirofti * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
256920b493Spirofti * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
266920b493Spirofti * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
276920b493Spirofti * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
286920b493Spirofti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
296920b493Spirofti * SUCH DAMAGE.
306920b493Spirofti */
316920b493Spirofti
326920b493Spirofti /*
336920b493Spirofti * Copyright (c) 2009 Sam Leffler, Errno Consulting
346920b493Spirofti * All rights reserved.
356920b493Spirofti *
366920b493Spirofti * Redistribution and use in source and binary forms, with or without
376920b493Spirofti * modification, are permitted provided that the following conditions
386920b493Spirofti * are met:
396920b493Spirofti * 1. Redistributions of source code must retain the above copyright
406920b493Spirofti * notice, this list of conditions and the following disclaimer.
416920b493Spirofti * 2. Redistributions in binary form must reproduce the above copyright
426920b493Spirofti * notice, this list of conditions and the following disclaimer in the
436920b493Spirofti * documentation and/or other materials provided with the distribution.
446920b493Spirofti *
456920b493Spirofti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
466920b493Spirofti * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
476920b493Spirofti * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
486920b493Spirofti * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
496920b493Spirofti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
506920b493Spirofti * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
516920b493Spirofti * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
526920b493Spirofti * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
536920b493Spirofti * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
546920b493Spirofti * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
556920b493Spirofti */
566920b493Spirofti
576920b493Spirofti /*
586920b493Spirofti * Copyright (c) 2015 Paul Irofti.
596920b493Spirofti *
606920b493Spirofti * Permission to use, copy, modify, and distribute this software for any
616920b493Spirofti * purpose with or without fee is hereby granted, provided that the above
626920b493Spirofti * copyright notice and this permission notice appear in all copies.
636920b493Spirofti *
646920b493Spirofti * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
656920b493Spirofti * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
666920b493Spirofti * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
676920b493Spirofti * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
686920b493Spirofti * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
696920b493Spirofti * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
706920b493Spirofti * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
716920b493Spirofti */
726920b493Spirofti
736920b493Spirofti
746920b493Spirofti #include <sys/param.h>
756920b493Spirofti #include <sys/systm.h>
766920b493Spirofti #include <sys/kernel.h>
776920b493Spirofti #include <sys/conf.h>
78c0cd3489Sguenther #include <sys/fcntl.h>
796920b493Spirofti #include <sys/stat.h>
806920b493Spirofti #include <sys/ioctl.h>
816920b493Spirofti #include <sys/mutex.h>
826920b493Spirofti #include <sys/buf.h>
836920b493Spirofti #include <sys/uio.h>
846920b493Spirofti #include <sys/malloc.h>
856920b493Spirofti #include <sys/device.h>
866920b493Spirofti #include <sys/disklabel.h>
876920b493Spirofti #include <sys/disk.h>
886920b493Spirofti #include <sys/syslog.h>
896920b493Spirofti #include <sys/proc.h>
906920b493Spirofti #include <sys/vnode.h>
916920b493Spirofti #include <sys/dkio.h>
926920b493Spirofti
936920b493Spirofti #include <machine/intr.h>
946920b493Spirofti #include <machine/bus.h>
956920b493Spirofti #include <machine/autoconf.h>
966920b493Spirofti
976920b493Spirofti #include <octeon/dev/iobusvar.h>
986920b493Spirofti #include <machine/octeonreg.h>
996920b493Spirofti #include <machine/octeonvar.h>
1006920b493Spirofti
1016920b493Spirofti
1026920b493Spirofti #define CFI_QRY_CMD_ADDR 0x55
1036920b493Spirofti #define CFI_QRY_CMD_DATA 0x98
1046920b493Spirofti
1056920b493Spirofti #define CFI_QRY_TTO_WRITE 0x1f
1066920b493Spirofti #define CFI_QRY_TTO_ERASE 0x21
1076920b493Spirofti #define CFI_QRY_MTO_WRITE 0x23
1086920b493Spirofti #define CFI_QRY_MTO_ERASE 0x25
1096920b493Spirofti
1106920b493Spirofti #define CFI_QRY_SIZE 0x27
1116920b493Spirofti #define CFI_QRY_NREGIONS 0x2c
1126920b493Spirofti #define CFI_QRY_REGION0 0x31
1136920b493Spirofti #define CFI_QRY_REGION(x) (CFI_QRY_REGION0 + (x) * 4)
1146920b493Spirofti
1156920b493Spirofti #define CFI_BCS_READ_ARRAY 0xff
1166920b493Spirofti
1176920b493Spirofti #define CFI_DISK_SECSIZE 512
1186920b493Spirofti #define CFI_DISK_MAXIOSIZE 65536
1196920b493Spirofti
1206920b493Spirofti #define AMDCF_MAP_SIZE 0x02000000
1216920b493Spirofti
1226920b493Spirofti #define CFI_AMD_BLOCK_ERASE 0x30
1236920b493Spirofti #define CFI_AMD_UNLOCK 0xaa
1246920b493Spirofti #define CFI_AMD_UNLOCK_ACK 0x55
1256920b493Spirofti #define CFI_AMD_PROGRAM 0xa0
1266920b493Spirofti #define CFI_AMD_RESET 0xf0
1276920b493Spirofti
1286920b493Spirofti #define AMD_ADDR_START 0x555
1296920b493Spirofti #define AMD_ADDR_ACK 0x2aa
1306920b493Spirofti
1316920b493Spirofti #define BOOTLOADER_ADDR 0xa0000
1326920b493Spirofti
1336920b493Spirofti struct cfi_region {
1346920b493Spirofti u_int r_blocks;
1356920b493Spirofti u_int r_blksz;
1366920b493Spirofti };
1376920b493Spirofti
1386920b493Spirofti struct amdcf_softc {
1396920b493Spirofti /* General disk infos */
1406920b493Spirofti struct device sc_dev;
1416920b493Spirofti struct disk sc_dk;
1426920b493Spirofti struct bufq sc_bufq;
1436920b493Spirofti struct buf *sc_bp;
1446920b493Spirofti
1456920b493Spirofti int sc_flags;
1466920b493Spirofti #define AMDCF_LOADED 0x10
1476920b493Spirofti
1486920b493Spirofti struct iobus_attach_args *sc_io;
1496920b493Spirofti bus_space_tag_t sc_iot;
1506920b493Spirofti bus_space_handle_t sc_ioh;
1516920b493Spirofti
1526920b493Spirofti size_t sc_size; /* Disk size in bytes */
1536920b493Spirofti u_int sc_regions; /* Erase regions. */
1546920b493Spirofti struct cfi_region *sc_region; /* Array of region info. */
1556920b493Spirofti
1566920b493Spirofti u_int sc_width;
1576920b493Spirofti u_int sc_shift;
1586920b493Spirofti u_int sc_mask;
1596920b493Spirofti
1606920b493Spirofti u_int sc_erase_timeout;
1616920b493Spirofti u_int sc_erase_max_timeout;
1626920b493Spirofti u_int sc_write_timeout;
1636920b493Spirofti u_int sc_write_max_timeout;
1646920b493Spirofti u_int sc_rstcmd;
1656920b493Spirofti
1666920b493Spirofti u_char *sc_wrbuf;
1676920b493Spirofti u_int sc_wrbufsz;
1686920b493Spirofti u_int sc_wrofs;
1696920b493Spirofti u_int sc_writing;
1706920b493Spirofti };
1716920b493Spirofti
1726920b493Spirofti int amdcf_match(struct device *, void *, void *);
1736920b493Spirofti void amdcf_attach(struct device *, struct device *, void *);
1746920b493Spirofti int amdcf_detach(struct device *, int);
1756920b493Spirofti
176471aeecfSnaddy const struct cfattach amdcf_ca = {
1776920b493Spirofti sizeof(struct amdcf_softc), amdcf_match, amdcf_attach, amdcf_detach
1786920b493Spirofti };
1796920b493Spirofti
1806920b493Spirofti struct cfdriver amdcf_cd = {
1816920b493Spirofti NULL, "amdcf", DV_DISK
1826920b493Spirofti };
1836920b493Spirofti
1846920b493Spirofti cdev_decl(amdcf);
1856920b493Spirofti bdev_decl(amdcf);
1866920b493Spirofti
1876920b493Spirofti #define amdcflookup(unit) (struct amdcf_softc *)disk_lookup(&amdcf_cd, (unit))
1886920b493Spirofti int amdcfgetdisklabel(dev_t, struct amdcf_softc *, struct disklabel *, int);
1896920b493Spirofti
1906920b493Spirofti void amdcfstart(void *);
1916920b493Spirofti void _amdcfstart(struct amdcf_softc *, struct buf *);
1926920b493Spirofti void amdcfdone(void *);
1936920b493Spirofti
1946920b493Spirofti void amdcf_disk_read(struct amdcf_softc *, struct buf *, off_t);
1956920b493Spirofti void amdcf_disk_write(struct amdcf_softc *, struct buf *, off_t);
1966920b493Spirofti
1976920b493Spirofti int cfi_block_start(struct amdcf_softc *, u_int);
1986920b493Spirofti int cfi_write_block(struct amdcf_softc *);
1996920b493Spirofti int cfi_erase_block(struct amdcf_softc *, u_int);
2006920b493Spirofti int cfi_block_finish(struct amdcf_softc *);
2016920b493Spirofti
2026920b493Spirofti void cfi_array_write(struct amdcf_softc *sc, u_int, u_int, u_int);
2036920b493Spirofti void cfi_amd_write(struct amdcf_softc *, u_int, u_int, u_int);
2046920b493Spirofti
2056920b493Spirofti uint8_t cfi_read(struct amdcf_softc *, bus_size_t, bus_size_t);
2066920b493Spirofti void cfi_write(struct amdcf_softc *, bus_size_t, bus_size_t, uint8_t);
2076920b493Spirofti int cfi_wait_ready(struct amdcf_softc *, u_int, u_int, u_int);
2086920b493Spirofti int cfi_make_cmd(uint8_t, u_int);
2096920b493Spirofti
2106920b493Spirofti int
amdcf_match(struct device * parent,void * match,void * aux)2116920b493Spirofti amdcf_match(struct device *parent, void *match, void *aux)
2126920b493Spirofti {
2136920b493Spirofti struct mainbus_attach_args *maa = aux;
2146920b493Spirofti struct cfdata *cf = match;
2156920b493Spirofti
2166920b493Spirofti if (strcmp(maa->maa_name, cf->cf_driver->cd_name) != 0)
2176920b493Spirofti return 0;
2186920b493Spirofti
2196920b493Spirofti /* Only for DSR machines */
2202bbf581cSvisa if (octeon_board != BOARD_DLINK_DSR_500)
2216920b493Spirofti return 0;
2226920b493Spirofti
2236920b493Spirofti return 1;
2246920b493Spirofti }
2256920b493Spirofti
2266920b493Spirofti void
amdcf_attach(struct device * parent,struct device * self,void * aux)2276920b493Spirofti amdcf_attach(struct device *parent, struct device *self, void *aux)
2286920b493Spirofti {
2296920b493Spirofti struct amdcf_softc *sc = (void *)self;
2306920b493Spirofti u_int blksz, blocks, r;
2316920b493Spirofti
2326920b493Spirofti sc->sc_io = aux;
2336920b493Spirofti sc->sc_iot = sc->sc_io->aa_bust;
2346920b493Spirofti
2356920b493Spirofti if (bus_space_map(sc->sc_iot, OCTEON_AMDCF_BASE, AMDCF_MAP_SIZE, 0,
2366920b493Spirofti &sc->sc_ioh)) {
2376920b493Spirofti printf(": can't map registers");
2386920b493Spirofti }
2396920b493Spirofti
2406920b493Spirofti /* should be detected in the generic driver */
2416920b493Spirofti sc->sc_width = 1;
2426920b493Spirofti sc->sc_shift = 2;
2436920b493Spirofti sc->sc_mask = 0x000000ff;
2446920b493Spirofti sc->sc_rstcmd = CFI_AMD_RESET;
2456920b493Spirofti
2466920b493Spirofti /* Initialize the Query Database from the CF */
2476920b493Spirofti cfi_array_write(sc, 0, 0, sc->sc_rstcmd);
2486920b493Spirofti cfi_write(sc, 0, CFI_QRY_CMD_ADDR, CFI_QRY_CMD_DATA);
2496920b493Spirofti
2506920b493Spirofti /* Get time-out values for erase and write. */
2516920b493Spirofti sc->sc_write_timeout = 1 << cfi_read(sc, 0, CFI_QRY_TTO_WRITE);
2526920b493Spirofti sc->sc_erase_timeout = 1 << cfi_read(sc, 0, CFI_QRY_TTO_ERASE);
2536920b493Spirofti sc->sc_write_max_timeout = 1 << cfi_read(sc, 0, CFI_QRY_MTO_WRITE);
2546920b493Spirofti sc->sc_erase_max_timeout = 1 << cfi_read(sc, 0, CFI_QRY_MTO_ERASE);
2556920b493Spirofti
2566920b493Spirofti /* Get the device size. */
2576920b493Spirofti sc->sc_size = 1U << cfi_read(sc, 0, CFI_QRY_SIZE);
2586920b493Spirofti printf(": AMD/Fujitsu %zu bytes\n", sc->sc_size);
2596920b493Spirofti
2606920b493Spirofti /* Get erase regions. */
2616920b493Spirofti sc->sc_regions = cfi_read(sc, 0, CFI_QRY_NREGIONS);
2626920b493Spirofti sc->sc_region = malloc(sc->sc_regions *
2636920b493Spirofti sizeof(struct cfi_region), M_TEMP, M_WAITOK | M_ZERO);
2646920b493Spirofti
2656920b493Spirofti for (r = 0; r < sc->sc_regions; r++) {
2666920b493Spirofti blocks = cfi_read(sc, 0, CFI_QRY_REGION(r)) |
2676920b493Spirofti (cfi_read(sc, 0, CFI_QRY_REGION(r) + 1) << 8);
2686920b493Spirofti sc->sc_region[r].r_blocks = blocks + 1;
2696920b493Spirofti
2706920b493Spirofti blksz = cfi_read(sc, 0, CFI_QRY_REGION(r) + 2) |
2716920b493Spirofti (cfi_read(sc, 0, CFI_QRY_REGION(r) + 3) << 8);
2726920b493Spirofti sc->sc_region[r].r_blksz = (blksz == 0) ? 128 :
2736920b493Spirofti blksz * 256;
2746920b493Spirofti }
2756920b493Spirofti
2766920b493Spirofti /* Reset the device to the default state */
2776920b493Spirofti cfi_array_write(sc, 0, 0, sc->sc_rstcmd);
2786920b493Spirofti
2796920b493Spirofti /*
2806920b493Spirofti * Initialize disk structures.
2816920b493Spirofti */
2826920b493Spirofti sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
2836920b493Spirofti bufq_init(&sc->sc_bufq, BUFQ_DEFAULT);
2846920b493Spirofti
2856920b493Spirofti /* Attach disk. */
2866920b493Spirofti disk_attach(&sc->sc_dev, &sc->sc_dk);
2876920b493Spirofti
2886920b493Spirofti }
2896920b493Spirofti
2906920b493Spirofti int
amdcf_detach(struct device * self,int flags)2916920b493Spirofti amdcf_detach(struct device *self, int flags)
2926920b493Spirofti {
2936920b493Spirofti struct amdcf_softc *sc = (struct amdcf_softc *)self;
2946920b493Spirofti
2956920b493Spirofti bufq_drain(&sc->sc_bufq);
2966920b493Spirofti
2976920b493Spirofti disk_gone(amdcfopen, self->dv_unit);
2986920b493Spirofti
2996920b493Spirofti /* Detach disk. */
3006920b493Spirofti bufq_destroy(&sc->sc_bufq);
3016920b493Spirofti disk_detach(&sc->sc_dk);
3026920b493Spirofti
3036920b493Spirofti return 0;
3046920b493Spirofti }
3056920b493Spirofti
3066920b493Spirofti
3076920b493Spirofti int
amdcfopen(dev_t dev,int flag,int fmt,struct proc * p)3086920b493Spirofti amdcfopen(dev_t dev, int flag, int fmt, struct proc *p)
3096920b493Spirofti {
3106920b493Spirofti struct amdcf_softc *sc;
3116920b493Spirofti int unit, part;
3126920b493Spirofti int error;
3136920b493Spirofti
3146920b493Spirofti unit = DISKUNIT(dev);
3156920b493Spirofti sc = amdcflookup(unit);
3166920b493Spirofti if (sc == NULL)
3176920b493Spirofti return ENXIO;
3186920b493Spirofti
3196920b493Spirofti /*
3206920b493Spirofti * If this is the first open of this device, add a reference
3216920b493Spirofti * to the adapter.
3226920b493Spirofti */
3236920b493Spirofti if ((error = disk_lock(&sc->sc_dk)) != 0)
3246920b493Spirofti goto out1;
3256920b493Spirofti
3266920b493Spirofti if (sc->sc_dk.dk_openmask != 0) {
3276920b493Spirofti /*
3286920b493Spirofti * If any partition is open, but the disk has been invalidated,
3296920b493Spirofti * disallow further opens.
3306920b493Spirofti */
3316920b493Spirofti if ((sc->sc_flags & AMDCF_LOADED) == 0) {
3326920b493Spirofti error = EIO;
3336920b493Spirofti goto out;
3346920b493Spirofti }
3356920b493Spirofti } else {
3366920b493Spirofti if ((sc->sc_flags & AMDCF_LOADED) == 0) {
3376920b493Spirofti sc->sc_flags |= AMDCF_LOADED;
3386920b493Spirofti
3396920b493Spirofti /* Load the partition info if not already loaded. */
3406920b493Spirofti if (amdcfgetdisklabel(dev, sc,
3416920b493Spirofti sc->sc_dk.dk_label, 0) == EIO) {
3426920b493Spirofti error = EIO;
3436920b493Spirofti goto out;
3446920b493Spirofti }
3456920b493Spirofti }
3466920b493Spirofti }
3476920b493Spirofti
3486920b493Spirofti part = DISKPART(dev);
3496920b493Spirofti
3506920b493Spirofti if ((error = disk_openpart(&sc->sc_dk, part, fmt, 1)) != 0)
3516920b493Spirofti goto out;
3526920b493Spirofti
3536920b493Spirofti disk_unlock(&sc->sc_dk);
3546920b493Spirofti device_unref(&sc->sc_dev);
3556920b493Spirofti return 0;
3566920b493Spirofti
3576920b493Spirofti out:
3586920b493Spirofti disk_unlock(&sc->sc_dk);
3596920b493Spirofti out1:
3606920b493Spirofti device_unref(&sc->sc_dev);
3616920b493Spirofti return error;
3626920b493Spirofti }
3636920b493Spirofti
3646920b493Spirofti /*
3656920b493Spirofti * Load the label information on the named device
3666920b493Spirofti */
3676920b493Spirofti int
amdcfgetdisklabel(dev_t dev,struct amdcf_softc * sc,struct disklabel * lp,int spoofonly)3686920b493Spirofti amdcfgetdisklabel(dev_t dev, struct amdcf_softc *sc, struct disklabel *lp,
3696920b493Spirofti int spoofonly)
3706920b493Spirofti {
3716920b493Spirofti memset(lp, 0, sizeof(struct disklabel));
3726920b493Spirofti
3736920b493Spirofti lp->d_secsize = DEV_BSIZE;
3746920b493Spirofti lp->d_nsectors = 1; /* bogus */
3756920b493Spirofti lp->d_ntracks = 1; /* bogus */
3766920b493Spirofti lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
3776920b493Spirofti lp->d_ncylinders = sc->sc_size / lp->d_secpercyl;
3786920b493Spirofti
3796920b493Spirofti strlcpy(lp->d_typename, "amdcf device", sizeof(lp->d_typename));
3806920b493Spirofti lp->d_type = DTYPE_SCSI; /* bogus type, can be anything */
3816920b493Spirofti strlcpy(lp->d_packname, "CFI Disk", sizeof(lp->d_packname));
3826920b493Spirofti DL_SETDSIZE(lp, sc->sc_size / DEV_BSIZE);
3836920b493Spirofti lp->d_version = 1;
3846920b493Spirofti
3856920b493Spirofti lp->d_magic = DISKMAGIC;
3866920b493Spirofti lp->d_magic2 = DISKMAGIC;
3876920b493Spirofti lp->d_checksum = dkcksum(lp);
3886920b493Spirofti
3896920b493Spirofti /* Call the generic disklabel extraction routine */
3906920b493Spirofti return readdisklabel(DISKLABELDEV(dev), amdcfstrategy, lp, spoofonly);
3916920b493Spirofti }
3926920b493Spirofti
3936920b493Spirofti int
amdcfclose(dev_t dev,int flag,int fmt,struct proc * p)3946920b493Spirofti amdcfclose(dev_t dev, int flag, int fmt, struct proc *p)
3956920b493Spirofti {
3966920b493Spirofti struct amdcf_softc *sc;
3976920b493Spirofti int part = DISKPART(dev);
3986920b493Spirofti
3996920b493Spirofti sc = amdcflookup(DISKUNIT(dev));
4006920b493Spirofti if (sc == NULL)
4016920b493Spirofti return ENXIO;
4026920b493Spirofti
4036920b493Spirofti disk_lock_nointr(&sc->sc_dk);
4046920b493Spirofti
4056920b493Spirofti disk_closepart(&sc->sc_dk, part, fmt);
4066920b493Spirofti
4076920b493Spirofti disk_unlock(&sc->sc_dk);
4086920b493Spirofti
4096920b493Spirofti device_unref(&sc->sc_dev);
4106920b493Spirofti return 0;
4116920b493Spirofti }
4126920b493Spirofti
4136920b493Spirofti int
amdcfread(dev_t dev,struct uio * uio,int flags)4146920b493Spirofti amdcfread(dev_t dev, struct uio *uio, int flags)
4156920b493Spirofti {
4166920b493Spirofti return (physio(amdcfstrategy, dev, B_READ, minphys, uio));
4176920b493Spirofti }
4186920b493Spirofti
4196920b493Spirofti int
amdcfwrite(dev_t dev,struct uio * uio,int flags)4206920b493Spirofti amdcfwrite(dev_t dev, struct uio *uio, int flags)
4216920b493Spirofti {
4226920b493Spirofti #ifdef AMDCF_DISK_WRITE_ENABLE
4236920b493Spirofti return (physio(amdcfstrategy, dev, B_WRITE, minphys, uio));
4246920b493Spirofti #else
4256920b493Spirofti return 0;
4266920b493Spirofti #endif
4276920b493Spirofti }
4286920b493Spirofti
4296920b493Spirofti void
amdcfstrategy(struct buf * bp)4306920b493Spirofti amdcfstrategy(struct buf *bp)
4316920b493Spirofti {
4326920b493Spirofti struct amdcf_softc *sc;
4336920b493Spirofti int s;
4346920b493Spirofti
4356920b493Spirofti sc = amdcflookup(DISKUNIT(bp->b_dev));
4366920b493Spirofti if (sc == NULL) {
4376920b493Spirofti bp->b_error = ENXIO;
4386920b493Spirofti goto bad;
4396920b493Spirofti }
4406920b493Spirofti /* If device invalidated (e.g. media change, door open), error. */
4416920b493Spirofti if ((sc->sc_flags & AMDCF_LOADED) == 0) {
4426920b493Spirofti bp->b_error = EIO;
4436920b493Spirofti goto bad;
4446920b493Spirofti }
4456920b493Spirofti
4466920b493Spirofti /* Validate the request. */
4476920b493Spirofti if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1)
4486920b493Spirofti goto done;
4496920b493Spirofti
4506920b493Spirofti /* Check that the number of sectors can fit in a byte. */
4516920b493Spirofti if ((bp->b_bcount / sc->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) {
4526920b493Spirofti bp->b_error = EINVAL;
4536920b493Spirofti goto bad;
4546920b493Spirofti }
4556920b493Spirofti
4566920b493Spirofti /* Queue transfer on drive, activate drive and controller if idle. */
4576920b493Spirofti bufq_queue(&sc->sc_bufq, bp);
4586920b493Spirofti s = splbio();
4596920b493Spirofti amdcfstart(sc);
4606920b493Spirofti splx(s);
4616920b493Spirofti device_unref(&sc->sc_dev);
4626920b493Spirofti return;
4636920b493Spirofti
4646920b493Spirofti bad:
4656920b493Spirofti bp->b_flags |= B_ERROR;
4666920b493Spirofti bp->b_resid = bp->b_bcount;
4676920b493Spirofti done:
4686920b493Spirofti s = splbio();
4696920b493Spirofti biodone(bp);
4706920b493Spirofti splx(s);
4716920b493Spirofti if (sc != NULL)
4726920b493Spirofti device_unref(&sc->sc_dev);
4736920b493Spirofti }
4746920b493Spirofti
4756920b493Spirofti int
amdcfioctl(dev_t dev,u_long xfer,caddr_t addr,int flag,struct proc * p)4766920b493Spirofti amdcfioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, struct proc *p)
4776920b493Spirofti {
4786920b493Spirofti struct amdcf_softc *sc;
4796920b493Spirofti struct disklabel *lp;
4806920b493Spirofti int error = 0;
4816920b493Spirofti
4826920b493Spirofti sc = amdcflookup(DISKUNIT(dev));
4836920b493Spirofti if (sc == NULL)
4846920b493Spirofti return ENXIO;
4856920b493Spirofti
4866920b493Spirofti if ((sc->sc_flags & AMDCF_LOADED) == 0) {
4876920b493Spirofti error = EIO;
4886920b493Spirofti goto exit;
4896920b493Spirofti }
4906920b493Spirofti
4916920b493Spirofti switch (xfer) {
4926920b493Spirofti case DIOCRLDINFO:
4936920b493Spirofti lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK);
4946920b493Spirofti amdcfgetdisklabel(dev, sc, lp, 0);
4956920b493Spirofti bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp));
4969df86521Sfcambus free(lp, M_TEMP, sizeof(*lp));
4976920b493Spirofti goto exit;
4986920b493Spirofti
4996920b493Spirofti case DIOCGPDINFO:
5006920b493Spirofti amdcfgetdisklabel(dev, sc, (struct disklabel *)addr, 1);
5016920b493Spirofti goto exit;
5026920b493Spirofti
5036920b493Spirofti case DIOCGDINFO:
5046920b493Spirofti *(struct disklabel *)addr = *(sc->sc_dk.dk_label);
5056920b493Spirofti goto exit;
5066920b493Spirofti
5076920b493Spirofti case DIOCGPART:
5086920b493Spirofti ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label;
5096920b493Spirofti ((struct partinfo *)addr)->part =
5106920b493Spirofti &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)];
5116920b493Spirofti goto exit;
5126920b493Spirofti
5136920b493Spirofti case DIOCWDINFO:
5146920b493Spirofti case DIOCSDINFO:
5156920b493Spirofti if ((flag & FWRITE) == 0) {
5166920b493Spirofti error = EBADF;
5176920b493Spirofti goto exit;
5186920b493Spirofti }
5196920b493Spirofti
5206920b493Spirofti if ((error = disk_lock(&sc->sc_dk)) != 0)
5216920b493Spirofti goto exit;
5226920b493Spirofti
5236920b493Spirofti error = setdisklabel(sc->sc_dk.dk_label,
5246920b493Spirofti (struct disklabel *)addr, sc->sc_dk.dk_openmask);
5256920b493Spirofti if (error == 0) {
5266920b493Spirofti if (xfer == DIOCWDINFO)
5276920b493Spirofti error = writedisklabel(DISKLABELDEV(dev),
5286920b493Spirofti amdcfstrategy, sc->sc_dk.dk_label);
5296920b493Spirofti }
5306920b493Spirofti
5316920b493Spirofti disk_unlock(&sc->sc_dk);
5326920b493Spirofti goto exit;
5336920b493Spirofti
5346920b493Spirofti default:
5356920b493Spirofti error = ENOTTY;
5366920b493Spirofti goto exit;
5376920b493Spirofti }
5386920b493Spirofti
5396920b493Spirofti #ifdef DIAGNOSTIC
5406920b493Spirofti panic("amdcfioctl: impossible");
5416920b493Spirofti #endif
5426920b493Spirofti
5436920b493Spirofti exit:
5446920b493Spirofti device_unref(&sc->sc_dev);
5456920b493Spirofti return error;
5466920b493Spirofti }
5476920b493Spirofti
5486920b493Spirofti /*
5496920b493Spirofti * Dump core after a system crash.
5506920b493Spirofti */
5516920b493Spirofti int
amdcfdump(dev_t dev,daddr_t blkno,caddr_t va,size_t size)5526920b493Spirofti amdcfdump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
5536920b493Spirofti {
5546920b493Spirofti return ENXIO;
5556920b493Spirofti }
5566920b493Spirofti
5576920b493Spirofti daddr_t
amdcfsize(dev_t dev)5586920b493Spirofti amdcfsize(dev_t dev)
5596920b493Spirofti {
5606920b493Spirofti struct amdcf_softc *sc;
5616920b493Spirofti struct disklabel *lp;
5626920b493Spirofti int part, omask;
5636920b493Spirofti daddr_t size;
5646920b493Spirofti
5656920b493Spirofti sc = amdcflookup(DISKUNIT(dev));
5666920b493Spirofti if (sc == NULL)
5676920b493Spirofti return (-1);
5686920b493Spirofti
5696920b493Spirofti part = DISKPART(dev);
5706920b493Spirofti omask = sc->sc_dk.dk_openmask & (1 << part);
5716920b493Spirofti
5726920b493Spirofti if (omask == 0 && amdcfopen(dev, 0, S_IFBLK, NULL) != 0) {
5736920b493Spirofti size = -1;
5746920b493Spirofti goto exit;
5756920b493Spirofti }
5766920b493Spirofti
5776920b493Spirofti lp = sc->sc_dk.dk_label;
5786920b493Spirofti size = DL_SECTOBLK(lp, DL_GETPSIZE(&lp->d_partitions[part]));
5796920b493Spirofti if (omask == 0 && amdcfclose(dev, 0, S_IFBLK, NULL) != 0)
5806920b493Spirofti size = -1;
5816920b493Spirofti
5826920b493Spirofti exit:
5836920b493Spirofti device_unref(&sc->sc_dev);
5846920b493Spirofti return size;
5856920b493Spirofti }
5866920b493Spirofti
5876920b493Spirofti
5886920b493Spirofti /*
5896920b493Spirofti * Queue a drive for I/O.
5906920b493Spirofti */
5916920b493Spirofti void
amdcfstart(void * arg)5926920b493Spirofti amdcfstart(void *arg)
5936920b493Spirofti {
5946920b493Spirofti struct amdcf_softc *sc = arg;
5956920b493Spirofti struct buf *bp;
5966920b493Spirofti
5976920b493Spirofti while ((bp = bufq_dequeue(&sc->sc_bufq)) != NULL) {
5986920b493Spirofti /* Transfer this buffer now. */
5996920b493Spirofti _amdcfstart(sc, bp);
6006920b493Spirofti }
6016920b493Spirofti }
6026920b493Spirofti
6036920b493Spirofti void
_amdcfstart(struct amdcf_softc * sc,struct buf * bp)6046920b493Spirofti _amdcfstart(struct amdcf_softc *sc, struct buf *bp)
6056920b493Spirofti {
6066920b493Spirofti off_t off;
6076920b493Spirofti struct partition *p;
6086920b493Spirofti
6096920b493Spirofti sc->sc_bp = bp;
6106920b493Spirofti
6116920b493Spirofti /* Fetch buffer's read/write offset */
6126920b493Spirofti p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)];
6136920b493Spirofti off = DL_GETPOFFSET(p) * sc->sc_dk.dk_label->d_secsize +
6146920b493Spirofti (u_int64_t)bp->b_blkno * DEV_BSIZE;
6156920b493Spirofti if (off > sc->sc_size) {
6166920b493Spirofti bp->b_flags |= B_ERROR;
6176920b493Spirofti bp->b_error = EIO;
6186920b493Spirofti return;
6196920b493Spirofti }
6206920b493Spirofti
6216920b493Spirofti /* Instrumentation. */
6226920b493Spirofti disk_busy(&sc->sc_dk);
6236920b493Spirofti
6246920b493Spirofti if (bp->b_flags & B_READ)
6256920b493Spirofti amdcf_disk_read(sc, bp, off);
6266920b493Spirofti #ifdef AMDCF_DISK_WRITE_ENABLE
6276920b493Spirofti else
6286920b493Spirofti amdcf_disk_write(sc, bp, off);
6296920b493Spirofti #endif
6306920b493Spirofti
6316920b493Spirofti amdcfdone(sc);
6326920b493Spirofti }
6336920b493Spirofti
6346920b493Spirofti void
amdcfdone(void * arg)6356920b493Spirofti amdcfdone(void *arg)
6366920b493Spirofti {
6376920b493Spirofti struct amdcf_softc *sc = arg;
6386920b493Spirofti struct buf *bp = sc->sc_bp;
6396920b493Spirofti
6406920b493Spirofti if (bp->b_error == 0)
6416920b493Spirofti bp->b_resid = 0;
6426920b493Spirofti else
6436920b493Spirofti bp->b_flags |= B_ERROR;
6446920b493Spirofti
6456920b493Spirofti disk_unbusy(&sc->sc_dk, (bp->b_bcount - bp->b_resid),
646d40269afSderaadt bp->b_blkno, (bp->b_flags & B_READ));
6476920b493Spirofti biodone(bp);
6486920b493Spirofti }
6496920b493Spirofti
6506920b493Spirofti void
amdcf_disk_read(struct amdcf_softc * sc,struct buf * bp,off_t off)6516920b493Spirofti amdcf_disk_read(struct amdcf_softc *sc, struct buf *bp, off_t off)
6526920b493Spirofti {
6536920b493Spirofti long resid;
6546920b493Spirofti
6556920b493Spirofti if (sc->sc_writing) {
6566920b493Spirofti bp->b_error = cfi_block_finish(sc);
6576920b493Spirofti if (bp->b_error) {
6586920b493Spirofti bp->b_flags |= B_ERROR;
6596920b493Spirofti return;
6606920b493Spirofti }
6616920b493Spirofti }
6626920b493Spirofti
6636920b493Spirofti resid = bp->b_bcount;
6646920b493Spirofti uint8_t *dp = (uint8_t *)bp->b_data;
6656920b493Spirofti while (resid > 0 && off < sc->sc_size) {
6666920b493Spirofti *dp++ = cfi_read(sc, off, 0);
6676920b493Spirofti off += 1, resid -= 1;
6686920b493Spirofti }
6696920b493Spirofti bp->b_resid = resid;
6706920b493Spirofti }
6716920b493Spirofti
6726920b493Spirofti void
amdcf_disk_write(struct amdcf_softc * sc,struct buf * bp,off_t off)6736920b493Spirofti amdcf_disk_write(struct amdcf_softc *sc, struct buf *bp, off_t off)
6746920b493Spirofti {
6756920b493Spirofti long resid;
6766920b493Spirofti u_int top;
6776920b493Spirofti
6786920b493Spirofti resid = bp->b_bcount;
6796920b493Spirofti while (resid > 0) {
6806920b493Spirofti /*
6816920b493Spirofti * Finish the current block if we're about to write
6826920b493Spirofti * to a different block.
6836920b493Spirofti */
6846920b493Spirofti if (sc->sc_writing) {
6856920b493Spirofti top = sc->sc_wrofs + sc->sc_wrbufsz;
6866920b493Spirofti if (off < sc->sc_wrofs || off >= top)
6876920b493Spirofti cfi_block_finish(sc);
6886920b493Spirofti }
6896920b493Spirofti
6906920b493Spirofti /* Start writing to a (new) block if applicable. */
6916920b493Spirofti if (!sc->sc_writing) {
6926920b493Spirofti bp->b_error = cfi_block_start(sc, off);
6936920b493Spirofti if (bp->b_error) {
6946920b493Spirofti bp->b_flags |= B_ERROR;
6956920b493Spirofti return;
6966920b493Spirofti }
6976920b493Spirofti }
6986920b493Spirofti
6996920b493Spirofti top = sc->sc_wrofs + sc->sc_wrbufsz;
7006920b493Spirofti bcopy(bp->b_data,
7016920b493Spirofti sc->sc_wrbuf + off - sc->sc_wrofs,
7026920b493Spirofti MIN(top - off, resid));
7036920b493Spirofti resid -= MIN(top - off, resid);
7046920b493Spirofti }
7056920b493Spirofti bp->b_resid = resid;
7066920b493Spirofti }
7076920b493Spirofti
7086920b493Spirofti /*
7096920b493Spirofti * Begin writing into a new block/sector. We read the sector into
7106920b493Spirofti * memory and keep updating that, until we move into another sector
7116920b493Spirofti * or the process stops writing. At that time we write the whole
7126920b493Spirofti * sector to flash (see cfi_block_finish).
7136920b493Spirofti */
7146920b493Spirofti int
cfi_block_start(struct amdcf_softc * sc,u_int ofs)7156920b493Spirofti cfi_block_start(struct amdcf_softc *sc, u_int ofs)
7166920b493Spirofti {
7176920b493Spirofti u_int rofs, rsz;
7186920b493Spirofti int r;
7196920b493Spirofti uint8_t *ptr;
7206920b493Spirofti
7216920b493Spirofti rofs = 0;
7226920b493Spirofti for (r = 0; r < sc->sc_regions; r++) {
7236920b493Spirofti rsz = sc->sc_region[r].r_blocks * sc->sc_region[r].r_blksz;
7246920b493Spirofti if (ofs < rofs + rsz)
7256920b493Spirofti break;
7266920b493Spirofti rofs += rsz;
7276920b493Spirofti }
7286920b493Spirofti if (r == sc->sc_regions)
7296920b493Spirofti return (EFAULT);
7306920b493Spirofti
7316920b493Spirofti sc->sc_wrbufsz = sc->sc_region[r].r_blksz;
7326920b493Spirofti sc->sc_wrbuf = malloc(sc->sc_wrbufsz, M_TEMP, M_WAITOK);
7336920b493Spirofti sc->sc_wrofs = ofs - (ofs - rofs) % sc->sc_wrbufsz;
7346920b493Spirofti
7356920b493Spirofti ptr = sc->sc_wrbuf;
7366920b493Spirofti /* Read the block from flash for byte-serving. */
7376920b493Spirofti for (r = 0; r < sc->sc_wrbufsz; r++)
7386920b493Spirofti *(ptr)++ = cfi_read(sc, sc->sc_wrofs + r, 0);
7396920b493Spirofti
7406920b493Spirofti sc->sc_writing = 1;
7416920b493Spirofti return (0);
7426920b493Spirofti }
7436920b493Spirofti
7446920b493Spirofti /*
7456920b493Spirofti * Finish updating the current block/sector by writing the compound
7466920b493Spirofti * set of changes to the flash.
7476920b493Spirofti */
7486920b493Spirofti int
cfi_block_finish(struct amdcf_softc * sc)7496920b493Spirofti cfi_block_finish(struct amdcf_softc *sc)
7506920b493Spirofti {
7516920b493Spirofti int error;
7526920b493Spirofti
7536920b493Spirofti error = cfi_write_block(sc);
7546920b493Spirofti free(sc->sc_wrbuf, M_TEMP, sc->sc_wrbufsz);
7556920b493Spirofti sc->sc_wrbuf = NULL;
7566920b493Spirofti sc->sc_wrbufsz = 0;
7576920b493Spirofti sc->sc_wrofs = 0;
7586920b493Spirofti sc->sc_writing = 0;
7596920b493Spirofti return (error);
7606920b493Spirofti }
7616920b493Spirofti
7626920b493Spirofti int
cfi_write_block(struct amdcf_softc * sc)7636920b493Spirofti cfi_write_block(struct amdcf_softc *sc)
7646920b493Spirofti {
7656920b493Spirofti uint8_t *ptr;
7666920b493Spirofti int error, i, s;
7676920b493Spirofti
7686920b493Spirofti if (sc->sc_wrofs > sc->sc_size)
7696920b493Spirofti panic("CFI: write offset (%x) bigger "
7706920b493Spirofti "than cfi array size (%zu)\n",
7716920b493Spirofti sc->sc_wrofs, sc->sc_size);
7726920b493Spirofti
7736920b493Spirofti if ((sc->sc_wrofs < BOOTLOADER_ADDR) ||
7746920b493Spirofti ((sc->sc_wrofs + sc->sc_wrbufsz) < BOOTLOADER_ADDR))
7756920b493Spirofti return EOPNOTSUPP;
7766920b493Spirofti
7776920b493Spirofti error = cfi_erase_block(sc, sc->sc_wrofs);
7786920b493Spirofti if (error)
7796920b493Spirofti goto out;
7806920b493Spirofti
7816920b493Spirofti /* Write the block. */
7826920b493Spirofti ptr = sc->sc_wrbuf;
7836920b493Spirofti
7846920b493Spirofti for (i = 0; i < sc->sc_wrbufsz; i += sc->sc_width) {
7856920b493Spirofti
7866920b493Spirofti /*
7876920b493Spirofti * Make sure the command to start a write and the
7886920b493Spirofti * actual write happens back-to-back without any
7896920b493Spirofti * excessive delays.
7906920b493Spirofti */
7916920b493Spirofti s = splbio();
7926920b493Spirofti
7936920b493Spirofti cfi_amd_write(sc, sc->sc_wrofs, AMD_ADDR_START,
7946920b493Spirofti CFI_AMD_PROGRAM);
7956920b493Spirofti /* Raw data do not use cfi_array_write */
7966920b493Spirofti cfi_write(sc, sc->sc_wrofs + i, 0, *(ptr)++);
7976920b493Spirofti
7986920b493Spirofti splx(s);
7996920b493Spirofti
8006920b493Spirofti error = cfi_wait_ready(sc, sc->sc_wrofs + i,
8016920b493Spirofti sc->sc_write_timeout, sc->sc_write_max_timeout);
8026920b493Spirofti if (error)
8036920b493Spirofti goto out;
8046920b493Spirofti }
8056920b493Spirofti
8066920b493Spirofti out:
8076920b493Spirofti cfi_array_write(sc, sc->sc_wrofs, 0, sc->sc_rstcmd);
8086920b493Spirofti return error;
8096920b493Spirofti }
8106920b493Spirofti
8116920b493Spirofti int
cfi_erase_block(struct amdcf_softc * sc,u_int offset)8126920b493Spirofti cfi_erase_block(struct amdcf_softc *sc, u_int offset)
8136920b493Spirofti {
8146920b493Spirofti int error = 0;
8156920b493Spirofti
8166920b493Spirofti if (offset > sc->sc_size)
8176920b493Spirofti panic("CFI: erase offset (%x) bigger "
8186920b493Spirofti "than cfi array size (%zu)\n",
8196920b493Spirofti sc->sc_wrofs, sc->sc_size);
8206920b493Spirofti
8216920b493Spirofti /* Erase the block. */
8226920b493Spirofti cfi_amd_write(sc, offset, 0, CFI_AMD_BLOCK_ERASE);
8236920b493Spirofti
8246920b493Spirofti error = cfi_wait_ready(sc, offset, sc->sc_erase_timeout,
8256920b493Spirofti sc->sc_erase_max_timeout);
8266920b493Spirofti
8276920b493Spirofti return error;
8286920b493Spirofti }
8296920b493Spirofti
8306920b493Spirofti
8316920b493Spirofti
8326920b493Spirofti int
cfi_wait_ready(struct amdcf_softc * sc,u_int ofs,u_int timeout,u_int count)8336920b493Spirofti cfi_wait_ready(struct amdcf_softc *sc, u_int ofs, u_int timeout, u_int count)
8346920b493Spirofti {
8356920b493Spirofti int done, error;
8366920b493Spirofti u_int st0 = 0, st = 0;
8376920b493Spirofti
8386920b493Spirofti done = 0;
8396920b493Spirofti error = 0;
8406920b493Spirofti
8416920b493Spirofti if (!timeout)
8426920b493Spirofti timeout = 100; /* Default to 100 uS */
8436920b493Spirofti if (!count)
8446920b493Spirofti count = 100; /* Max timeout is 10 mS */
8456920b493Spirofti
8466920b493Spirofti while (!done && !error && count) {
8476920b493Spirofti DELAY(timeout);
8486920b493Spirofti
8496920b493Spirofti count--;
8506920b493Spirofti
8516920b493Spirofti /*
8526920b493Spirofti * read sc->sc_width bytes, and check for toggle bit.
8536920b493Spirofti */
8546920b493Spirofti st0 = cfi_read(sc, ofs, 0);
8556920b493Spirofti st = cfi_read(sc, ofs, 0);
8566920b493Spirofti done = ((st & cfi_make_cmd(0x40, sc->sc_mask)) ==
8576920b493Spirofti (st0 & cfi_make_cmd(0x40, sc->sc_mask))) ? 1 : 0;
8586920b493Spirofti
8596920b493Spirofti break;
8606920b493Spirofti }
8616920b493Spirofti if (!done && !error)
8626920b493Spirofti error = ETIMEDOUT;
8636920b493Spirofti if (error)
8646920b493Spirofti printf("\nerror=%d (st 0x%x st0 0x%x) at offset=%x\n",
8656920b493Spirofti error, st, st0, ofs);
8666920b493Spirofti return error;
8676920b493Spirofti }
8686920b493Spirofti
8696920b493Spirofti /*
8706920b493Spirofti * cfi_array_write
8716920b493Spirofti * fill "bus width" word with value of var data by array mask sc->sc_mask
8726920b493Spirofti */
8736920b493Spirofti void
cfi_array_write(struct amdcf_softc * sc,u_int ofs,u_int addr,u_int data)8746920b493Spirofti cfi_array_write(struct amdcf_softc *sc, u_int ofs, u_int addr, u_int data)
8756920b493Spirofti {
8766920b493Spirofti data &= 0xff;
8776920b493Spirofti cfi_write(sc, ofs, addr, cfi_make_cmd(data, sc->sc_mask));
8786920b493Spirofti }
8796920b493Spirofti
8806920b493Spirofti void
cfi_amd_write(struct amdcf_softc * sc,u_int ofs,u_int addr,u_int data)8816920b493Spirofti cfi_amd_write(struct amdcf_softc *sc, u_int ofs, u_int addr, u_int data)
8826920b493Spirofti {
8836920b493Spirofti cfi_array_write(sc, ofs, AMD_ADDR_START, CFI_AMD_UNLOCK);
8846920b493Spirofti cfi_array_write(sc, ofs, AMD_ADDR_ACK, CFI_AMD_UNLOCK_ACK);
8856920b493Spirofti cfi_array_write(sc, ofs, addr, data);
8866920b493Spirofti }
8876920b493Spirofti
8886920b493Spirofti
8896920b493Spirofti
8906920b493Spirofti /*
8916920b493Spirofti * The following routines assume width=1 and shift=2 as that is
8926920b493Spirofti * the case on the Octeon DSR machines.
8936920b493Spirofti * If this assumption fails a new detection routine should be written
8946920b493Spirofti * and called during attach.
8956920b493Spirofti */
8966920b493Spirofti uint8_t
cfi_read(struct amdcf_softc * sc,bus_size_t base,bus_size_t offset)8976920b493Spirofti cfi_read(struct amdcf_softc *sc, bus_size_t base, bus_size_t offset)
8986920b493Spirofti {
8996920b493Spirofti return bus_space_read_1(sc->sc_iot, sc->sc_ioh,
9006920b493Spirofti base | (offset * sc->sc_shift));
9016920b493Spirofti }
9026920b493Spirofti
9036920b493Spirofti void
cfi_write(struct amdcf_softc * sc,bus_size_t base,bus_size_t offset,uint8_t val)9046920b493Spirofti cfi_write(struct amdcf_softc *sc, bus_size_t base, bus_size_t offset,
9056920b493Spirofti uint8_t val)
9066920b493Spirofti {
9076920b493Spirofti bus_space_write_1(sc->sc_iot, sc->sc_ioh,
9086920b493Spirofti base | (offset * sc->sc_shift), val);
9096920b493Spirofti }
9106920b493Spirofti
9116920b493Spirofti int
cfi_make_cmd(uint8_t cmd,u_int mask)9126920b493Spirofti cfi_make_cmd(uint8_t cmd, u_int mask)
9136920b493Spirofti {
9146920b493Spirofti int i;
9156920b493Spirofti u_int data = 0;
9166920b493Spirofti
9176920b493Spirofti for (i = 0; i < sizeof(int); i ++) {
9186920b493Spirofti if (mask & (0xff << (i*8)))
9196920b493Spirofti data |= cmd << (i*8);
9206920b493Spirofti }
9216920b493Spirofti
9226920b493Spirofti return data;
9236920b493Spirofti }
924