1*7991f5a7Sandvar /* $NetBSD: ace.c,v 1.5 2021/07/24 21:31:32 andvar Exp $ */
25f7e80a8Spooka
35f7e80a8Spooka /*-
45f7e80a8Spooka * Copyright (c) 2010 The NetBSD Foundation, Inc.
55f7e80a8Spooka * Copyright (c) 1999 The NetBSD Foundation, Inc.
65f7e80a8Spooka * All rights reserved.
75f7e80a8Spooka *
85f7e80a8Spooka * This code was written by Alessandro Forin and Neil Pittman
95f7e80a8Spooka * at Microsoft Research and contributed to The NetBSD Foundation
105f7e80a8Spooka * by Microsoft Corporation.
115f7e80a8Spooka *
125f7e80a8Spooka * Redistribution and use in source and binary forms, with or without
135f7e80a8Spooka * modification, are permitted provided that the following conditions
145f7e80a8Spooka * are met:
155f7e80a8Spooka * 1. Redistributions of source code must retain the above copyright
165f7e80a8Spooka * notice, this list of conditions and the following disclaimer.
175f7e80a8Spooka * 2. Redistributions in binary form must reproduce the above copyright
185f7e80a8Spooka * notice, this list of conditions and the following disclaimer in the
195f7e80a8Spooka * documentation and/or other materials provided with the distribution.
205f7e80a8Spooka *
215f7e80a8Spooka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
225f7e80a8Spooka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
235f7e80a8Spooka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
245f7e80a8Spooka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
255f7e80a8Spooka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
265f7e80a8Spooka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
275f7e80a8Spooka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
285f7e80a8Spooka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
295f7e80a8Spooka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
305f7e80a8Spooka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
315f7e80a8Spooka * POSSIBILITY OF SUCH DAMAGE.
325f7e80a8Spooka */
335f7e80a8Spooka
345f7e80a8Spooka /* --------------------------------------------------------------------------
355f7e80a8Spooka *
365f7e80a8Spooka * Module:
375f7e80a8Spooka *
385f7e80a8Spooka * ace.c
395f7e80a8Spooka *
405f7e80a8Spooka * Purpose:
415f7e80a8Spooka *
425f7e80a8Spooka * Driver for the Xilinx System ACE CompactFlash Solution
435f7e80a8Spooka *
445f7e80a8Spooka * Author:
455f7e80a8Spooka * A. Forin (sandrof)
465f7e80a8Spooka *
475f7e80a8Spooka * References:
485f7e80a8Spooka * "System ACE CompactFlash Solution", Advance Product Specification
495f7e80a8Spooka * Document DS080 Version 1.5 April 5, 2002. Xilinx Corp.
505f7e80a8Spooka * Available at http://www.xilinx.com
515f7e80a8Spooka *
525f7e80a8Spooka * "CF+ and CompactFlash Specification", Revision 4.1, 02/16/2007.
535f7e80a8Spooka * CompactFlash Association.
545f7e80a8Spooka * Available at http://www.compactflash.org
555f7e80a8Spooka * --------------------------------------------------------------------------
565f7e80a8Spooka */
575f7e80a8Spooka
585f7e80a8Spooka #include <lib/libsa/stand.h>
595f7e80a8Spooka #include <lib/libkern/libkern.h>
605f7e80a8Spooka #include <machine/emipsreg.h>
615f7e80a8Spooka
625f7e80a8Spooka #include <sys/param.h>
635f7e80a8Spooka #include <sys/disklabel.h>
645f7e80a8Spooka #include <sys/endian.h>
655f7e80a8Spooka
665f7e80a8Spooka #include "common.h"
675f7e80a8Spooka #include "ace.h"
6876c86da9Schristos #include "start.h"
695f7e80a8Spooka
705f7e80a8Spooka #define NSAC 2
715f7e80a8Spooka #define SAC0 ((struct _Sac *)IDE_DEFAULT_ADDRESS)
725f7e80a8Spooka #define SAC1 ((struct _Sac *)(IDE_DEFAULT_ADDRESS+256))
735f7e80a8Spooka
745f7e80a8Spooka #define CF_SECBITS 9
755f7e80a8Spooka #define CF_SECTOR_SIZE (1 << CF_SECBITS)
765f7e80a8Spooka
775f7e80a8Spooka
785f7e80a8Spooka /* Error codes
795f7e80a8Spooka */
805f7e80a8Spooka #define FAILED(x) (x < 0)
815f7e80a8Spooka #define S_OK (0)
825f7e80a8Spooka #define E_INVALID_PARAMETER (-1)
835f7e80a8Spooka #define E_DISK_RESET_FAILED (-2)
845f7e80a8Spooka #define E_NO_MEDIA_IN_DRIVE (-3)
855f7e80a8Spooka #define E_TIMED_OUT (-4)
865f7e80a8Spooka
875f7e80a8Spooka /* Utilities
885f7e80a8Spooka */
895f7e80a8Spooka #if defined(DEBUG)
905f7e80a8Spooka int acedebug = 2;
916f51a051Schristos #define DBGME(lev,x) \
926f51a051Schristos do \
936f51a051Schristos if (lev >= acedebug) { \
946f51a051Schristos x; \
956f51a051Schristos } \
966f51a051Schristos while (/*CONSTCOND*/0)
975f7e80a8Spooka #else
985f7e80a8Spooka #define DBGME(lev,x)
995f7e80a8Spooka #endif
1005f7e80a8Spooka
1015f7e80a8Spooka #if defined(DEBUG)
1025f7e80a8Spooka typedef char *NAME;
1035f7e80a8Spooka typedef struct _REGDESC {
1045f7e80a8Spooka NAME RegisterName;
1055f7e80a8Spooka NAME BitNames[32];
1065f7e80a8Spooka } REGDESC, *PREGDESC;
1075f7e80a8Spooka
1085f7e80a8Spooka static void SysacePrintRegister(const REGDESC *Desc, uint32_t Value);
1095f7e80a8Spooka
SysacePrintRegister(const REGDESC * Desc,uint32_t Value)1105f7e80a8Spooka static void SysacePrintRegister(const REGDESC *Desc, uint32_t Value)
1115f7e80a8Spooka {
1125f7e80a8Spooka int i;
1135f7e80a8Spooka printf("\t%s %x =", Desc->RegisterName, Value);
1145f7e80a8Spooka for (i = 31; i >= 0; i--) {
1155f7e80a8Spooka if (Value & (1 << i))
1165f7e80a8Spooka printf(" %s",
1175f7e80a8Spooka (Desc->BitNames[i]) ? Desc->BitNames[i] : "?");
1185f7e80a8Spooka }
1195f7e80a8Spooka printf("\n");
1205f7e80a8Spooka }
1215f7e80a8Spooka
SysaceDumpRegisters(struct _Sac * Interface)1225f7e80a8Spooka static void SysaceDumpRegisters(struct _Sac *Interface)
1235f7e80a8Spooka {
1245f7e80a8Spooka const REGDESC Control_Names =
1255f7e80a8Spooka { "Control",
1265f7e80a8Spooka {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1275f7e80a8Spooka "RST", // 0x00010000
1285f7e80a8Spooka "BUS8", // 0x00020000
1295f7e80a8Spooka "BUS16", // 0x00040000
1305f7e80a8Spooka "BUS32", // 0x00080000
1315f7e80a8Spooka "IRQ", // 0x00100000
1325f7e80a8Spooka "BRDY", // 0x00200000
1335f7e80a8Spooka "IMSK0", // 0x00400000
1345f7e80a8Spooka "IMSK1", // 0x00800000
1355f7e80a8Spooka "TD0", // 0x0f000000
1365f7e80a8Spooka "TD1", // 0x0f000000
1375f7e80a8Spooka "TD2", // 0x0f000000
1385f7e80a8Spooka "TD3", // 0x0f000000
1395f7e80a8Spooka "BUFW8", // 0x10000000
1405f7e80a8Spooka "BUFW16", // 0x20000000
1415f7e80a8Spooka "BUFW32", // 0x40000000
1425f7e80a8Spooka "DEBUG"} // 0x80000000
1435f7e80a8Spooka };
1445f7e80a8Spooka
1455f7e80a8Spooka const REGDESC STATUS_Names =
1465f7e80a8Spooka { "STATUS",
1475f7e80a8Spooka {"CFGLOCK", // 0x00000001
1485f7e80a8Spooka "MPULOCK", // 0x00000002
1495f7e80a8Spooka "CFGERROR", // 0x00000004
1505f7e80a8Spooka "CFCERROR", // 0x00000008
1515f7e80a8Spooka "CFDETECT", // 0x00000010
1525f7e80a8Spooka "DATABUFRDY", // 0x00000020
1535f7e80a8Spooka "DATABUFWRITE", //0x00000040
1545f7e80a8Spooka "CFGDONE", // 0x00000080
1555f7e80a8Spooka "RDYFORCFCMD", // 0x00000100
1565f7e80a8Spooka "CFGMODEPIN", // 0x00000200
1575f7e80a8Spooka 0,0,0,
1585f7e80a8Spooka "CFGADDRPIN0", // 0x0000e000
1595f7e80a8Spooka "CFGADDRPIN1", // 0x0000e000
1605f7e80a8Spooka "CFGADDRPIN2", // 0x0000e000
1615f7e80a8Spooka 0,
1625f7e80a8Spooka "CFBSY", // 0x00020000
1635f7e80a8Spooka "CFRDY", // 0x00040000
1645f7e80a8Spooka "CFDWF", // 0x00080000
1655f7e80a8Spooka "CFDSC", // 0x00100000
1665f7e80a8Spooka "CFDRQ", // 0x00200000
1675f7e80a8Spooka "CFCORR", // 0x00400000
1685f7e80a8Spooka "CFERR", // 0x00800000
1695f7e80a8Spooka 0,}
1705f7e80a8Spooka };
1715f7e80a8Spooka
1725f7e80a8Spooka const REGDESC ERRORREG_Names =
1735f7e80a8Spooka { "ERRORREG",
1745f7e80a8Spooka {"CARDRESETERR", // 0x00000001
1755f7e80a8Spooka "CARDRDYERR", // 0x00000002
1765f7e80a8Spooka "CARDREADERR", // 0x00000004
1775f7e80a8Spooka "CARDWRITEERR", // 0x00000008
1785f7e80a8Spooka "SECTORRDYERR", // 0x00000010
1795f7e80a8Spooka "CFGADDRERR", // 0x00000020
1805f7e80a8Spooka "CFGFAILED", // 0x00000040
1815f7e80a8Spooka "CFGREADERR", // 0x00000080
1825f7e80a8Spooka "CFGINSTRERR", // 0x00000100
1835f7e80a8Spooka "CFGINITERR", // 0x00000200
1845f7e80a8Spooka 0,
1855f7e80a8Spooka "CFBBK", // 0x00000800
1865f7e80a8Spooka "CFUNC", // 0x00001000
1875f7e80a8Spooka "CFIDNF", // 0x00002000
1885f7e80a8Spooka "CFABORT", // 0x00004000
1895f7e80a8Spooka "CFAMNF", // 0x00008000
1905f7e80a8Spooka 0,}
1915f7e80a8Spooka };
1925f7e80a8Spooka
1935f7e80a8Spooka const NAME CommandNames[8] =
1945f7e80a8Spooka { "0", // 0x0000
1955f7e80a8Spooka "RESETMEMCARD", // 0x0100
1965f7e80a8Spooka "IDENTIFYMEMCARD", // 0x0200
1975f7e80a8Spooka "READMEMCARDDATA", // 0x0300
1985f7e80a8Spooka "WRITEMEMCARDDATA", // 0x0400
1995f7e80a8Spooka "5", // 0x0500
2005f7e80a8Spooka "ABORT", // 0x0600
2015f7e80a8Spooka "7" // 0x0700
2025f7e80a8Spooka };
2035f7e80a8Spooka
2045f7e80a8Spooka const REGDESC CONTROLREG_Names =
2055f7e80a8Spooka { "CONTROLREG",
2065f7e80a8Spooka {"FORCELOCKREQ", // 0x00000001
2075f7e80a8Spooka "LOCKREQ", // 0x00000002
2085f7e80a8Spooka "FORCECFGADDR", // 0x00000004
2095f7e80a8Spooka "FORCECFGMODE", // 0x00000008
2105f7e80a8Spooka "CFGMODE", // 0x00000010
2115f7e80a8Spooka "CFGSTART", // 0x00000020
2125f7e80a8Spooka "CFGSEL_MPU", // 0x00000040
2135f7e80a8Spooka "CFGRESET", // 0x00000080
2145f7e80a8Spooka "DATABUFRDYIRQ", // 0x00000100
2155f7e80a8Spooka "ERRORIRQ", // 0x00000200
2165f7e80a8Spooka "CFGDONEIRQ", // 0x00000400
2175f7e80a8Spooka "RESETIRQ", // 0x00000800
2185f7e80a8Spooka "CFGPROG", // 0x00001000
2195f7e80a8Spooka "CFGADDR_B0", // 0x00002000
2205f7e80a8Spooka "CFGADDR_B1", // 0x00004000
2215f7e80a8Spooka "CFGADDR_B2", // 0x00008000
2225f7e80a8Spooka 0,}
2235f7e80a8Spooka };
2245f7e80a8Spooka
2255f7e80a8Spooka const REGDESC FATSTATREG_Names =
2265f7e80a8Spooka { "FATSTATREG",
2275f7e80a8Spooka {"MBRVALID", // 0x00000001
2285f7e80a8Spooka "PBRVALID", // 0x00000002
2295f7e80a8Spooka "MBRFAT12", // 0x00000004
2305f7e80a8Spooka "PBRFAT12", // 0x00000008
2315f7e80a8Spooka "MBRFAT16", // 0x00000010
2325f7e80a8Spooka "PBRFAT16", // 0x00000020
2335f7e80a8Spooka "CALCFAT12", // 0x00000040
2345f7e80a8Spooka "CALCFAT16", // 0x00000080
2355f7e80a8Spooka 0, }
2365f7e80a8Spooka };
2375f7e80a8Spooka
2385f7e80a8Spooka printf("Sysace@%p:\n", Interface);
2395f7e80a8Spooka printf("\tTag %x\n", Interface->Tag);
2405f7e80a8Spooka SysacePrintRegister(&Control_Names, Interface->Control);
2415f7e80a8Spooka printf("\tBUSMODEREG %x\n", Interface->BUSMODEREG);
2425f7e80a8Spooka SysacePrintRegister(&STATUS_Names, Interface->STATUS);
2435f7e80a8Spooka SysacePrintRegister(&ERRORREG_Names, Interface->ERRORREG);
2445f7e80a8Spooka printf("\tCFGLBAREG %x\n", Interface->CFGLBAREG);
2455f7e80a8Spooka printf("\tMPULBAREG %x\n", Interface->MPULBAREG);
2465f7e80a8Spooka printf("\tVERSIONREG %x\n", Interface->VERSIONREG);
2475f7e80a8Spooka printf("\tSECCNTCMDREG %x = %s cnt=%d\n", Interface->SECCNTCMDREG,
2485f7e80a8Spooka CommandNames[(Interface->SECCNTCMDREG >> 8)&7],
2495f7e80a8Spooka Interface->SECCNTCMDREG & SAC_SECCCNT);
2505f7e80a8Spooka SysacePrintRegister(&CONTROLREG_Names, Interface->CONTROLREG);
2515f7e80a8Spooka SysacePrintRegister(&FATSTATREG_Names, Interface->FATSTATREG);
2525f7e80a8Spooka }
2535f7e80a8Spooka
2545f7e80a8Spooka #else
2555f7e80a8Spooka #define SysaceDumpRegisters(_c_)
2565f7e80a8Spooka #endif
2575f7e80a8Spooka
2585f7e80a8Spooka /* Reset the device and the interface
2595f7e80a8Spooka */
SysaceInitialize(struct _Sac * Interface)2605f7e80a8Spooka static int SysaceInitialize(struct _Sac *Interface)
2615f7e80a8Spooka {
2625f7e80a8Spooka /* 16bit mode etc etc */
2635f7e80a8Spooka uint32_t BusMode, Control;
2645f7e80a8Spooka
2655f7e80a8Spooka /* reset our interface */
2665f7e80a8Spooka Interface->Control = SAC_RST;
2675f7e80a8Spooka Delay(200);
2685f7e80a8Spooka
2695f7e80a8Spooka /* repeat on both byte lanes */
2705f7e80a8Spooka Interface->BUSMODEREG = SAC_MODE16 | (SAC_MODE16 << 8);
2715f7e80a8Spooka Delay(1);
2725f7e80a8Spooka
2735f7e80a8Spooka /* check what our interface does and what the SysACE expects */
2745f7e80a8Spooka Control = Interface->Control;
2755f7e80a8Spooka BusMode = Interface->BUSMODEREG;
2765f7e80a8Spooka
2775f7e80a8Spooka /* get them to agree */
2785f7e80a8Spooka if (BusMode & SAC_MODE16)
2795f7e80a8Spooka {
2805f7e80a8Spooka Interface->Control = Control | SAC_BUS16;
2815f7e80a8Spooka Interface->Control = Interface->Control & ~SAC_BUS8;
2825f7e80a8Spooka }
2835f7e80a8Spooka else
2845f7e80a8Spooka {
2855f7e80a8Spooka Interface->Control = Control | SAC_BUS8;
2865f7e80a8Spooka Interface->Control = Interface->Control & ~SAC_BUS16;
2875f7e80a8Spooka }
2885f7e80a8Spooka
2895f7e80a8Spooka /* check that it worked */
2905f7e80a8Spooka BusMode = Interface->BUSMODEREG;
2915f7e80a8Spooka Control = Interface->Control;
2925f7e80a8Spooka
2935f7e80a8Spooka if (((BusMode & SAC_MODE16) == 0) && ((Control & SAC_BUS8) == 0)) return E_DISK_RESET_FAILED;
2945f7e80a8Spooka if (((BusMode & SAC_MODE16) > 0) && ((Control & SAC_BUS16) == 0)) return E_DISK_RESET_FAILED;
2955f7e80a8Spooka
2965f7e80a8Spooka /* interrupts off for now */
2975f7e80a8Spooka Interface->Control &= ~SAC_INTMASK;
2985f7e80a8Spooka #define SAC_INTERRUPTS (SAC_DATABUFRDYIRQ | SAC_ERRORIRQ )// | SAC_CFGDONEIRQ)
2995f7e80a8Spooka Control = Interface->CONTROLREG;
3005f7e80a8Spooka Control = (Control & ~SAC_INTERRUPTS) | SAC_RESETIRQ | SAC_FORCECFGMODE;
3015f7e80a8Spooka Interface->CONTROLREG = Control;
3025f7e80a8Spooka Interface->CONTROLREG = Control & ~SAC_RESETIRQ;
3035f7e80a8Spooka
3045f7e80a8Spooka /* no command */
3055f7e80a8Spooka Interface->MPULBAREG = 0;
3065f7e80a8Spooka
3075f7e80a8Spooka return S_OK;
3085f7e80a8Spooka }
3095f7e80a8Spooka
3105f7e80a8Spooka /* Take control of the ACE datapath
3115f7e80a8Spooka */
SysaceLock(struct _Sac * Interface)3125f7e80a8Spooka static int SysaceLock(struct _Sac *Interface)
3135f7e80a8Spooka {
3145f7e80a8Spooka uint32_t Status;
3155f7e80a8Spooka int i;
3165f7e80a8Spooka
3175f7e80a8Spooka /* Locked already?
3185f7e80a8Spooka */
3195f7e80a8Spooka Status = Interface->STATUS;
3205f7e80a8Spooka if (Status & SAC_MPULOCK)
3215f7e80a8Spooka return TRUE;
3225f7e80a8Spooka
3235f7e80a8Spooka /* Request lock
3245f7e80a8Spooka */
3255f7e80a8Spooka Interface->CONTROLREG |= SAC_LOCKREQ;
3265f7e80a8Spooka
3275f7e80a8Spooka /* Spin a bit until we get it
3285f7e80a8Spooka */
3295f7e80a8Spooka for (i = 0; i < 200; i++) {
3305f7e80a8Spooka Status = Interface->STATUS;
3315f7e80a8Spooka if (Status & SAC_MPULOCK)
3325f7e80a8Spooka return TRUE;
3335f7e80a8Spooka Delay(100);
3345f7e80a8Spooka DBGME(0,printf("Sysace::Lock loops.. (st=%x)\n",Status));
3355f7e80a8Spooka }
3365f7e80a8Spooka
3375f7e80a8Spooka /* oopsie!
3385f7e80a8Spooka */
3395f7e80a8Spooka DBGME(3,printf("Sysace::Lock timeout (st=%x)\n",Status));
3405f7e80a8Spooka SysaceDumpRegisters(Interface);
3415f7e80a8Spooka return FALSE;
3425f7e80a8Spooka }
3435f7e80a8Spooka
3445f7e80a8Spooka /* Release control of the ACE datapath
3455f7e80a8Spooka */
SysaceUnlock(struct _Sac * Interface)3465f7e80a8Spooka static int SysaceUnlock(struct _Sac *Interface)
3475f7e80a8Spooka {
3485f7e80a8Spooka uint32_t Status;
3495f7e80a8Spooka int i;
3505f7e80a8Spooka
3515f7e80a8Spooka /* Clear reset
3525f7e80a8Spooka */
3535f7e80a8Spooka Interface->CONTROLREG &= ~SAC_CFGRESET;
3545f7e80a8Spooka
3555f7e80a8Spooka /* Unlocked already?
3565f7e80a8Spooka */
3575f7e80a8Spooka Status = Interface->STATUS;
3585f7e80a8Spooka if (0 == (Status & SAC_MPULOCK))
3595f7e80a8Spooka return TRUE;
3605f7e80a8Spooka
3615f7e80a8Spooka /* Request unlock
3625f7e80a8Spooka */
3635f7e80a8Spooka Interface->CONTROLREG &= ~SAC_LOCKREQ;
3645f7e80a8Spooka
3655f7e80a8Spooka /* Spin a bit until we get it
3665f7e80a8Spooka */
3675f7e80a8Spooka for (i = 0; i < 200; i++) {
3685f7e80a8Spooka Status = Interface->STATUS;
3695f7e80a8Spooka if (0 == (Status & SAC_MPULOCK))
3705f7e80a8Spooka return TRUE;
3715f7e80a8Spooka Delay(100);
3725f7e80a8Spooka DBGME(0,printf("Sysace::Unlock loops.. (st=%x)\n",Status));
3735f7e80a8Spooka }
3745f7e80a8Spooka
3755f7e80a8Spooka /* oopsie!
3765f7e80a8Spooka */
3775f7e80a8Spooka DBGME(3,printf("Sysace::Unlock timeout (st=%x)\n",Status));
3785f7e80a8Spooka SysaceDumpRegisters(Interface);
3795f7e80a8Spooka return FALSE;
3805f7e80a8Spooka }
3815f7e80a8Spooka
3825f7e80a8Spooka /* Check if the ACE is waiting for a comamnd
3835f7e80a8Spooka */
3845f7e80a8Spooka #define SysaceReadyForCommand(_i_) ((_i_)->STATUS & SAC_RDYFORCFCMD)
3855f7e80a8Spooka
3865f7e80a8Spooka /* Check if the ACE is executing a comamnd
3875f7e80a8Spooka */
3885f7e80a8Spooka #define SysaceBusyWithCommand(_i_) ((_i_)->STATUS & SAC_CFBSY)
3895f7e80a8Spooka
3905f7e80a8Spooka /* Turn on interrupts from the ACE
3915f7e80a8Spooka */
3925f7e80a8Spooka #define SysaceInton(_i_) { \
3935f7e80a8Spooka (_i_)->CONTROLREG |= SAC_INTERRUPTS; \
3945f7e80a8Spooka (_i_)->Control |= SAC_INTMASK; \
3955f7e80a8Spooka }
3965f7e80a8Spooka
3975f7e80a8Spooka /* Turn off interrupts from the ACE
3985f7e80a8Spooka */
3995f7e80a8Spooka #define SysaceIntoff(_i_) { \
4005f7e80a8Spooka (_i_)->CONTROLREG &= ~SAC_INTERRUPTS; \
4015f7e80a8Spooka (_i_)->Control &= ~SAC_INTMASK; \
4025f7e80a8Spooka }
4035f7e80a8Spooka
4045f7e80a8Spooka /* Start a command on the ACE, such as read or identify.
4055f7e80a8Spooka */
SysaceStartCommand(struct _Sac * Interface,uint32_t Command,uint32_t Lba,uint32_t nSectors)4065f7e80a8Spooka static int SysaceStartCommand(struct _Sac *Interface,
4075f7e80a8Spooka uint32_t Command,
4085f7e80a8Spooka uint32_t Lba,
4095f7e80a8Spooka uint32_t nSectors)
4105f7e80a8Spooka {
4115f7e80a8Spooka int sc = E_DISK_RESET_FAILED;
4125f7e80a8Spooka
4135f7e80a8Spooka /* Lock it if not already
4145f7e80a8Spooka */
4155f7e80a8Spooka if (!SysaceLock(Interface)) {
4165f7e80a8Spooka /* printed already */
4175f7e80a8Spooka return sc;
4185f7e80a8Spooka }
4195f7e80a8Spooka
4205f7e80a8Spooka /* Is there a CF inserted
4215f7e80a8Spooka */
4225f7e80a8Spooka if (! (Interface->STATUS & SAC_CFDETECT)) {
4235f7e80a8Spooka /* NB: Not a failure state */
4245f7e80a8Spooka DBGME(2,printf("Sysace:: no media (st=%x)\n",Interface->STATUS));
4255f7e80a8Spooka return E_NO_MEDIA_IN_DRIVE;
4265f7e80a8Spooka }
4275f7e80a8Spooka
4285f7e80a8Spooka /* Is it ready for a command
4295f7e80a8Spooka */
4305f7e80a8Spooka if (!SysaceReadyForCommand(Interface)) {
4315f7e80a8Spooka DBGME(3,printf("Sysace:: not ready (st=%x)\n",Interface->STATUS));
4325f7e80a8Spooka SysaceDumpRegisters(Interface);
4335f7e80a8Spooka return sc;
4345f7e80a8Spooka }
4355f7e80a8Spooka
4365f7e80a8Spooka /* sector number and command
4375f7e80a8Spooka */
4385f7e80a8Spooka Interface->MPULBAREG = Lba;
4395f7e80a8Spooka Interface->SECCNTCMDREG = (uint16_t)(Command | (nSectors & SAC_SECCCNT));
4405f7e80a8Spooka
4415f7e80a8Spooka /* re-route the chip
4425f7e80a8Spooka * NB: The word "RESET" is actually not much of a misnomer.
4435f7e80a8Spooka * The chip was designed for a one-shot execution only, at reset time,
4445f7e80a8Spooka * namely loading the configuration data into the FPGA. So..
4455f7e80a8Spooka */
4465f7e80a8Spooka Interface->CONTROLREG |= SAC_CFGRESET;
4475f7e80a8Spooka return S_OK;
4485f7e80a8Spooka }
4495f7e80a8Spooka
4505f7e80a8Spooka
4515f7e80a8Spooka /* "Interrupt service routine"
4525f7e80a8Spooka */
SysAce_isr(struct _Sac * Interface)4535f7e80a8Spooka static void SysAce_isr ( struct _Sac *Interface )
4545f7e80a8Spooka {
4555f7e80a8Spooka uint32_t Control;
4565f7e80a8Spooka
4575f7e80a8Spooka /* Turn off interrupts and ACK them
4585f7e80a8Spooka */
4595f7e80a8Spooka SysaceIntoff(Interface);
4605f7e80a8Spooka
4615f7e80a8Spooka Control = Interface->CONTROLREG & (~(SAC_RESETIRQ|SAC_INTERRUPTS));
4625f7e80a8Spooka Interface->CONTROLREG = Control | SAC_RESETIRQ;
4635f7e80a8Spooka Interface->CONTROLREG = Control;
4645f7e80a8Spooka }
4655f7e80a8Spooka
SysAce_wait(struct _Sac * Interface)4665f7e80a8Spooka static int SysAce_wait(struct _Sac *Interface)
4675f7e80a8Spooka {
4685f7e80a8Spooka int i;
4695f7e80a8Spooka for (i = 0; i < 30000; i++) {
4705f7e80a8Spooka if (Interface->STATUS & SAC_DATABUFRDY) {
4715f7e80a8Spooka SysAce_isr(Interface);
4725f7e80a8Spooka return S_OK;
4735f7e80a8Spooka }
4745f7e80a8Spooka Delay(100);
4755f7e80a8Spooka }
4765f7e80a8Spooka return E_TIMED_OUT;
4775f7e80a8Spooka }
4785f7e80a8Spooka
4795f7e80a8Spooka
4805f7e80a8Spooka /* Read NBLOCKS blocks of 512 bytes each,
4815f7e80a8Spooka * starting at block number STARTSECTOR,
4825f7e80a8Spooka * into the buffer BUFFER.
4835f7e80a8Spooka * Return 0 if ok, -1 otherwise.
4845f7e80a8Spooka */
SysAce_read(struct _Sac * Interface,char * Buffer,uint32_t StartSector,uint32_t nBlocks)4855f7e80a8Spooka static int SysAce_read(struct _Sac * Interface, char *Buffer, uint32_t StartSector, uint32_t nBlocks)
4865f7e80a8Spooka {
4875f7e80a8Spooka int sc = S_OK;
4885f7e80a8Spooka uint32_t Size, SizeThisTime;
4895f7e80a8Spooka uint32_t Status = 0, SizeRead = 0;
4905f7e80a8Spooka unsigned int i, j;
4915f7e80a8Spooka
4925f7e80a8Spooka Size = nBlocks << CF_SECBITS;
4935f7e80a8Spooka
4945f7e80a8Spooka DBGME(1,printf("Sysace Read(%p %x %x)\n",
4955f7e80a8Spooka Buffer, StartSector, nBlocks));
4965f7e80a8Spooka
4975f7e80a8Spooka /* Repeat until we are done or error
4985f7e80a8Spooka */
4995f7e80a8Spooka while (sc == S_OK) {
5005f7e80a8Spooka
5015f7e80a8Spooka /* .. one sector at a time
5025f7e80a8Spooka * BUGBUG Supposedly we can do up to 256 sectors?
5035f7e80a8Spooka */
5045f7e80a8Spooka SizeThisTime = Size;
5055f7e80a8Spooka if (SizeThisTime > CF_SECTOR_SIZE)
5065f7e80a8Spooka SizeThisTime = CF_SECTOR_SIZE;
5075f7e80a8Spooka
5085f7e80a8Spooka /* Start a new sector read
5095f7e80a8Spooka */
5105f7e80a8Spooka SysaceInton(Interface);
5115f7e80a8Spooka sc = SysaceStartCommand(Interface,
5125f7e80a8Spooka SAC_CMD_READMEMCARDDATA,
5135f7e80a8Spooka StartSector,
5145f7e80a8Spooka 1);
5155f7e80a8Spooka /* And wait until done, if ok
5165f7e80a8Spooka */
5175f7e80a8Spooka if (!FAILED(sc)) {
5185f7e80a8Spooka sc = SysAce_wait(Interface);
5195f7e80a8Spooka }
5205f7e80a8Spooka
5215f7e80a8Spooka /* Are we doing ok
5225f7e80a8Spooka */
5235f7e80a8Spooka if (!FAILED(sc)) {
5245f7e80a8Spooka
5255f7e80a8Spooka /* Get the data out of the ACE
5265f7e80a8Spooka */
5275f7e80a8Spooka for (i = 0; i < SizeThisTime; i += 4) {
5285f7e80a8Spooka
5295f7e80a8Spooka /* Make sure the FIFO is ready
5305f7e80a8Spooka */
5315f7e80a8Spooka for (j = 0; j < 100; j++) {
5325f7e80a8Spooka Status = Interface->STATUS;
5335f7e80a8Spooka if (Status & SAC_DATABUFRDY)
5345f7e80a8Spooka break;
5355f7e80a8Spooka Delay(10);
5365f7e80a8Spooka }
5375f7e80a8Spooka
5385f7e80a8Spooka /* Got it?
5395f7e80a8Spooka */
5405f7e80a8Spooka if (Status & SAC_DATABUFRDY) {
5415f7e80a8Spooka uint32_t Data32;
5425f7e80a8Spooka
5435f7e80a8Spooka Data32 = Interface->DATABUFREG[0];
5445f7e80a8Spooka Data32 = le32toh(Data32);
5455f7e80a8Spooka DBGME(0,printf(" %x", Data32));
5465f7e80a8Spooka if (0 == (0xf & (i+4))) DBGME(0,printf("\n"));
5475f7e80a8Spooka memcpy(Buffer+i, &Data32, 4);
5485f7e80a8Spooka }
5495f7e80a8Spooka else
5505f7e80a8Spooka {
5515f7e80a8Spooka /* Ooops, get out of here
5525f7e80a8Spooka */
5535f7e80a8Spooka DBGME(3,printf("Sysace::READ timeout\n"));
5545f7e80a8Spooka SysaceDumpRegisters(Interface);
5555f7e80a8Spooka sc = E_TIMED_OUT;
5565f7e80a8Spooka break;
5575f7e80a8Spooka }
5585f7e80a8Spooka }
5595f7e80a8Spooka
5605f7e80a8Spooka /* Still doing ok?
5615f7e80a8Spooka */
5625f7e80a8Spooka if (!FAILED(sc)) {
5635f7e80a8Spooka StartSector += 1;
5645f7e80a8Spooka Buffer += SizeThisTime;
5655f7e80a8Spooka SizeRead += SizeThisTime;
5665f7e80a8Spooka Size -= SizeThisTime;
5675f7e80a8Spooka }
5685f7e80a8Spooka }
5695f7e80a8Spooka
5705f7e80a8Spooka /* Free the ACE for the JTAG, just in case */
5715f7e80a8Spooka SysaceUnlock(Interface);
5725f7e80a8Spooka
5735f7e80a8Spooka /* Are we done yet?
5745f7e80a8Spooka */
5755f7e80a8Spooka if (Size == 0)
5765f7e80a8Spooka break;
5775f7e80a8Spooka }
5785f7e80a8Spooka
5795f7e80a8Spooka return sc;
5805f7e80a8Spooka }
5815f7e80a8Spooka
5825f7e80a8Spooka /* Exported interface
5835f7e80a8Spooka */
5845f7e80a8Spooka struct ace_softc {
5855f7e80a8Spooka struct _Sac *sc_dp; /* I/O regs */
5865f7e80a8Spooka int sc_part; /* disk partition number */
5875f7e80a8Spooka struct disklabel sc_label; /* disk label for this disk */
5885f7e80a8Spooka };
5895f7e80a8Spooka
5905f7e80a8Spooka #define RF_PROTECTED_SECTORS 64 /* XXX refer to <.../rf_optnames.h> */
5915f7e80a8Spooka
aceprobe(int unit)5925f7e80a8Spooka int aceprobe(int unit)
5935f7e80a8Spooka {
5945f7e80a8Spooka struct _Sac *Sac;
5955f7e80a8Spooka
5965f7e80a8Spooka if (unit == 0)
5975f7e80a8Spooka Sac = SAC0;
5985f7e80a8Spooka else if (unit == 1)
5995f7e80a8Spooka Sac = SAC1;
6005f7e80a8Spooka else
6015f7e80a8Spooka return E_INVALID_PARAMETER;
6025f7e80a8Spooka
6035f7e80a8Spooka /* Check the tag to see if its there
6045f7e80a8Spooka */
6055f7e80a8Spooka if ((Sac->Tag & SAC_TAG) != PMTTAG_SYSTEM_ACE) {
6065f7e80a8Spooka DBGME(3,printf("init_ace: bad tag (%x != %x) @x%p\n",
6075f7e80a8Spooka Sac->Tag, PMTTAG_SYSTEM_ACE, Sac));
6085f7e80a8Spooka return E_INVALID_PARAMETER;
6095f7e80a8Spooka }
6105f7e80a8Spooka
6115f7e80a8Spooka return S_OK;
6125f7e80a8Spooka }
6135f7e80a8Spooka
6145f7e80a8Spooka /* aceopen("", ctlr, unit, part);
6155f7e80a8Spooka */
6165f7e80a8Spooka int
aceopen(struct open_file * f,...)6175f7e80a8Spooka aceopen(struct open_file *f, ...)
6185f7e80a8Spooka {
6195f7e80a8Spooka int ctlr, unit, part;
6205f7e80a8Spooka struct _Sac *Sac;
6215f7e80a8Spooka
6225f7e80a8Spooka struct ace_softc *sc;
6235f7e80a8Spooka struct disklabel *lp;
6245f7e80a8Spooka int i;
6255f7e80a8Spooka char *msg;
6265f7e80a8Spooka char buf[DEV_BSIZE];
62776c86da9Schristos size_t cnt;
6285f7e80a8Spooka va_list ap;
6295f7e80a8Spooka
6305f7e80a8Spooka va_start(ap, f);
6315f7e80a8Spooka
6325f7e80a8Spooka ctlr = va_arg(ap, int);
6335f7e80a8Spooka unit = va_arg(ap, int);
6345f7e80a8Spooka part = va_arg(ap, int);
6355f7e80a8Spooka va_end(ap);
6365f7e80a8Spooka
6375f7e80a8Spooka if (ctlr != 0 || unit >= NSAC || part >= 8)
6385f7e80a8Spooka return (ENXIO);
6395f7e80a8Spooka
6405f7e80a8Spooka /* Is it there, does it work.
6415f7e80a8Spooka */
6425f7e80a8Spooka Sac = (unit == 0) ? SAC0 : SAC1;
6435f7e80a8Spooka i = aceprobe(unit);
6445f7e80a8Spooka if (i < 0)
6455f7e80a8Spooka goto Bad;
6465f7e80a8Spooka
6475f7e80a8Spooka if (SysaceInitialize(Sac) < 0) {
6485f7e80a8Spooka DBGME(3,printf("ace%d: no reset @x%p\n", unit, Sac));
6495f7e80a8Spooka Bad:
6505f7e80a8Spooka printf("open failed\n");
6515f7e80a8Spooka return (ENXIO);
6525f7e80a8Spooka }
6535f7e80a8Spooka
6545f7e80a8Spooka /* Yep, go ahead.
6555f7e80a8Spooka */
6565f7e80a8Spooka sc = alloc(sizeof(struct ace_softc));
6575f7e80a8Spooka memset(sc, 0, sizeof(struct ace_softc));
6585f7e80a8Spooka f->f_devdata = (void *)sc;
6595f7e80a8Spooka
6605f7e80a8Spooka sc->sc_dp = Sac;
6615f7e80a8Spooka sc->sc_part = part;
6625f7e80a8Spooka
6635f7e80a8Spooka /* try to read disk label and partition table information */
6645f7e80a8Spooka lp = &sc->sc_label;
6655f7e80a8Spooka lp->d_secsize = DEV_BSIZE;
6665f7e80a8Spooka lp->d_secpercyl = 1;
6675f7e80a8Spooka lp->d_npartitions = MAXPARTITIONS;
6685f7e80a8Spooka lp->d_partitions[part].p_offset = 0;
6695f7e80a8Spooka lp->d_partitions[part].p_size = 0x7fffffff;
6705f7e80a8Spooka
6715f7e80a8Spooka i = acestrategy(sc, F_READ, (daddr_t)LABELSECTOR, DEV_BSIZE, buf, &cnt);
6725f7e80a8Spooka if (i || cnt != DEV_BSIZE) {
6735f7e80a8Spooka DBGME(3,printf("ace%d: error reading disk label\n", unit));
6745f7e80a8Spooka goto bad;
6755f7e80a8Spooka }
6765f7e80a8Spooka msg = getdisklabel(buf, lp);
6775f7e80a8Spooka if (msg) {
6785f7e80a8Spooka /* If no label, just assume 0 and return */
6795f7e80a8Spooka return (0);
6805f7e80a8Spooka }
6815f7e80a8Spooka
6825f7e80a8Spooka if (part >= lp->d_npartitions || lp->d_partitions[part].p_size == 0) {
6835f7e80a8Spooka bad:
6845f7e80a8Spooka dealloc(sc, sizeof(struct ace_softc));
6855f7e80a8Spooka DBGME(3,printf("ace%d: bad part %d\n", unit, part));
6865f7e80a8Spooka return (ENXIO);
6875f7e80a8Spooka }
6885f7e80a8Spooka return (0);
6895f7e80a8Spooka }
6905f7e80a8Spooka
6915f7e80a8Spooka #ifndef LIBSA_NO_DEV_CLOSE
6925f7e80a8Spooka int
aceclose(struct open_file * f)6935f7e80a8Spooka aceclose(struct open_file *f)
6945f7e80a8Spooka {
6955f7e80a8Spooka dealloc(f->f_devdata, sizeof(struct ace_softc));
6965f7e80a8Spooka f->f_devdata = (void *)0;
6975f7e80a8Spooka return (0);
6985f7e80a8Spooka }
6995f7e80a8Spooka #endif
7005f7e80a8Spooka
7015f7e80a8Spooka int
acestrategy(void * devdata,int rw,daddr_t bn,size_t reqcnt,void * addr,size_t * cnt)7025f7e80a8Spooka acestrategy(
7035f7e80a8Spooka void *devdata,
7045f7e80a8Spooka int rw,
7055f7e80a8Spooka daddr_t bn,
7065f7e80a8Spooka size_t reqcnt,
7075f7e80a8Spooka void *addr,
708*7991f5a7Sandvar size_t *cnt) /* out: number of bytes transferred */
7095f7e80a8Spooka {
7105f7e80a8Spooka struct ace_softc *sc = (struct ace_softc *)devdata;
7115f7e80a8Spooka int part = sc->sc_part;
7125f7e80a8Spooka struct partition *pp = &sc->sc_label.d_partitions[part];
7135f7e80a8Spooka int s;
7145f7e80a8Spooka uint32_t sector;
7155f7e80a8Spooka
7165f7e80a8Spooka #if 0 //useless?
7175f7e80a8Spooka if (rw != F_READ)
7185f7e80a8Spooka return (EINVAL);
7195f7e80a8Spooka #endif
7205f7e80a8Spooka
7215f7e80a8Spooka /*
7225f7e80a8Spooka * Partial-block transfers not handled.
7235f7e80a8Spooka */
7245f7e80a8Spooka if (reqcnt & (DEV_BSIZE - 1)) {
7255f7e80a8Spooka *cnt = 0;
7265f7e80a8Spooka return (EINVAL);
7275f7e80a8Spooka }
7285f7e80a8Spooka
7295f7e80a8Spooka /*
7305f7e80a8Spooka * Compute starting sector
7315f7e80a8Spooka */
7325f7e80a8Spooka sector = bn;
7335f7e80a8Spooka sector += pp->p_offset;
7345f7e80a8Spooka if (pp->p_fstype == FS_RAID)
7355f7e80a8Spooka sector += RF_PROTECTED_SECTORS;
7365f7e80a8Spooka
7375f7e80a8Spooka /* read */
7385f7e80a8Spooka s = SysAce_read(sc->sc_dp,addr,sector,reqcnt >> CF_SECBITS);
7395f7e80a8Spooka
7405f7e80a8Spooka if (s < 0)
7415f7e80a8Spooka return (EIO);
7425f7e80a8Spooka
7435f7e80a8Spooka /* BUGBUG there's no validation we don't fall off the deep end */
7445f7e80a8Spooka *cnt = reqcnt;
7455f7e80a8Spooka return (0);
7465f7e80a8Spooka }
7475f7e80a8Spooka
748