xref: /netbsd-src/sys/arch/emips/stand/common/ace.c (revision 7991f5a7b8fc83a3d55dc2a1767cca3b84103969)
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