| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916 |
- /*
- * Copyright : (C) 2022 Phytium Information Technology, Inc.
- * All Rights Reserved.
- *
- * This program is OPEN SOURCE software: you can redistribute it and/or modify it
- * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
- * either version 1.0 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the Phytium Public License for more details.
- *
- *
- * FilePath: fsata.c
- * Date: 2022-02-10 14:55:11
- * LastEditTime: 2022-02-18 09:05:09
- * Description: This files is for sata ctrl function implementation
- *
- * Modify History:
- * Ver Who Date Changes
- * ----- ------ -------- --------------------------------------
- */
- #include <string.h>
- #include <stdlib.h>
- #include "ftypes.h"
- #include "fassert.h"
- #include "fcache.h"
- #include "fdebug.h"
- #include "fsleep.h"
- #include "fswap.h"
- #include "fsata.h"
- #include "fsata_hw.h"
- /************************** Constant Definitions *****************************/
- /**************************** Type Definitions *******************************/
- /***************** Macros (Inline Functions) Definitions *********************/
- /************************** Function Prototypes ******************************/
- /************************** Variable Definitions *****************************/
- #define FSATA_DEBUG_TAG "SATA"
- #define FSATA_ERROR(format, ...) FT_DEBUG_PRINT_E(FSATA_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FSATA_WARN(format, ...) FT_DEBUG_PRINT_W(FSATA_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FSATA_INFO(format, ...) FT_DEBUG_PRINT_I(FSATA_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FSATA_DEBUG(format, ...) FT_DEBUG_PRINT_D(FSATA_DEBUG_TAG, format, ##__VA_ARGS__)
- #ifndef MAX_SATA_BLOCKS_READ_WRITE
- #define MAX_SATA_BLOCKS_READ_WRITE 0x80
- #endif
- /* Maximum timeouts for each event */
- #define WAIT_MS_RESET 1000
- #define WAIT_MS_TFD 20000 /* task file data transfer is not busy */
- #define WAIT_MS_DATAIO 20000
- #define WAIT_MS_LINKUP 200
- static FError FSataAhciDataIO(FSataCtrl *instance_p, u8 port, u8 *fis,
- int fis_len, u8 *buf, int buf_len, boolean is_ncq, boolean is_write);
- /**
- * @name: FSataAhciPortBase
- * @msg: get port x base address
- * @param {uintptr} base_address FSata base address
- * @param {u32} port sata port number
- * @return {uintptr} port x base address
- */
- static uintptr FSataAhciPortBase(uintptr base_address, u32 port)
- {
- return (base_address + 0x100 + (port * 0x80));
- }
- /**
- * @name: FSataWaitCmdCompleted
- * @msg: read register status and wait command execution is completed
- * @param {uintptr} reg FSata register
- * @param {int} timeout_msec wait timeout value
- * @param {u32} sign register status flag bit
- * @return {int} return 0 if command execute success, return -1 if command execute timeout
- */
- static int FSataWaitCmdCompleted(uintptr reg, int timeout_msec, u32 sign)
- {
- int i;
- for (i = 0; (FtIn32(reg)& sign) && (i < timeout_msec); i++)
- {
- fsleep_millisec(1);
- }
- return (i < timeout_msec) ? 0 : -1;
- }
- /**
- * @name: FSataAhciLinkUp
- * @msg: check sata ahci port link status
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance.
- * @param {u8} port, port number
- * @return {int} return FSATA_SUCCESS if successful, return others if failed
- */
- static FError FSataAhciLinkUp(FSataCtrl *instance_p, u8 port)
- {
- u32 reg_val;
- int i = 0;
- uintptr port_base_addr = instance_p->port[port].port_base_addr;
- /*
- * Bring up SATA link.
- * SATA link bringup time is usually less than 1 ms; only very
- * rarely has it taken between 1-2 ms. Never seen it above 2 ms.
- */
- while (i < WAIT_MS_LINKUP)
- {
- reg_val = FSATA_READ_REG32(port_base_addr, FSATA_PORT_SCR_STAT);
- if ((reg_val & FSATA_PORT_SCR_STAT_DET_MASK) == FSATA_PORT_SCR_STAT_DET_PHYRDY)
- return FSATA_SUCCESS;
- fsleep_microsec(1000);
- i++;
- }
- return FSATA_ERR_TIMEOUT;
- }
- /**
- * @name: FSataAhciInquiry
- * @msg: inquiry sata information
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance.
- * @param {u8} port, port number
- * @return {FError} return FSATA_SUCCESS if successful, return others if failed
- */
- static FError FSataAhciInquiry(FSataCtrl *instance_p, u8 port)
- {
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- FError ret = FSATA_SUCCESS;
- u16 *idbuf;
- /* 64位需要预留给内存池更大的空间 */
- static u16 tmpid[FSATA_ID_WORDS] __attribute__((aligned(128))) = {0};
- u8 fis[20];
- /* Preset the FIS */
- memset(fis, 0, sizeof(fis));
- fis[0] = FSATA_FIS_REG_HOST_TO_DEVICE; /* Register Host to Device FIS */
- fis[1] = FSATA_FIS_REG_HOST_TO_DEVICE_C;
- fis[2] = FSATA_CMD_IDENTIFY_DEVICE; /* Command byte. */
- ret = FSataAhciDataIO(instance_p, port, fis, sizeof(fis),
- (u8 *)tmpid, FSATA_ID_WORDS * 2, FALSE, FALSE);
- if (ret != FSATA_SUCCESS)
- {
- FSATA_ERROR("FSataAhciInquiry: command failure. ret = %#x", ret);
- return FSATA_ERR_OPERATION;
- }
- instance_p->ataid[port] = tmpid;
- return FSATA_SUCCESS;
- }
- /**
- * @name: FSataIdentityCopy
- * @msg: parse sata Identity information to vendor, product, revision
- * @param {unsigned char } *dest, pointer to the destination address.
- * @param {unsigned char } *src, pointer to the source address.
- * @param {u32} len, parse length.
- * @return {void}
- */
- static void FSataIdentityCopy(unsigned char *dest, unsigned char *src, u32 len)
- {
- FASSERT(dest != NULL);
- FASSERT(src != NULL);
- FASSERT(len != 0);
- u32 start, end;
- start = 0;
- while (start < len)
- {
- if (src[start] != 0x20)/* character is not sapce */
- break;
- start++;
- }
- end = len - 1;
- while (end > start)
- {
- if (src[end] != 0x20)/* character is not sapce */
- break;
- end--;
- }
- for (; start <= end; start++)
- *dest ++ = src[start];
- *dest = '\0';
- }
- /**
- * @name: FSataIdToSectors
- * @msg: parse sata Identity information to capacity.
- * @param {u16} *id, pointer to Identity information .
- * @return {u64} capacity
- */
- static u64 FSataIdToSectors(u16 *id)
- {
- if (FSataIdHasLba(id))
- {
- if (FSataIdHasLba48(id))
- return FSATA_ID_U64(id, FSATA_ID_LBA48_SECTORS);
- else
- return (u64)(FSATA_ID_U32(id, FSATA_ID_LBA_SECTORS));
- }
- else
- {
- return 0;
- }
- }
- /**
- * @name: FSataIdStrCopy
- * @msg: swap sata Identity information
- * @param {u16} *dest, pointer to the destination address.
- * @param {u16} *src, pointer to the source address.
- * @param {int} len, swap length.
- * @return {void}
- */
- static void FSataIdStrCopy(u16 *dest, u16 *src, int len)
- {
- int i;
- for (i = 0; i < len / 2; i++)
- dest[i] = __swab16(src[i]);
- }
- /**
- * @name: FSataBlockToMB
- * @msg: Converts the number of blocks in 512 byte to 0.1MB
- * @param {unsigned long} block_count, block count.
- * @param {unsigned long} mul_by, multiple value.
- * @param {int} div_by, divided value.
- * @return {unsigned long} convert value
- */
- static unsigned long FSataBlockToMB(unsigned long block_count, unsigned long mul, int div)
- {
- unsigned long bc_quot, bc_rem;
- /* x * m / d == x / d * m + (x % d) * m / d */
- bc_quot = (block_count >> div); /* upper > div bit */
- bc_rem = block_count - (bc_quot << div); /* low div bit */
- return (bc_quot * mul + ((bc_rem * mul) >> div));
- }
- /**
- * @name: FSataInfoPrint
- * @msg: printf sata information
- * @param {FSataInfo} *dev_desc, pointer to the FSata information.
- * @return {void}
- */
- void FSataInfoPrint(FSataInfo *dev_desc)
- {
- unsigned long lba512; /* number of blocks if 512bytes block size */
- if (dev_desc->type == FSATA_DEV_TYPE_UNKNOWN)
- {
- FSATA_INFO("not available");
- return;
- }
- if (dev_desc->if_type == FSATA_IF_TYPE_SCSI)
- {
- FSATA_INFO("Vendor: %s Prod: %s Rev: %s",
- dev_desc->vendor,
- dev_desc->product,
- dev_desc->revision);
- }
- if (dev_desc->type == FSATA_DEV_TYPE_HARDDISK)
- {
- FSATA_INFO("Type: Hard Disk");
- }
- if ((dev_desc->lba > 0L) && (dev_desc->blksz > 0L))
- {
- unsigned long mb, mb_quot, mb_rem, gb, gb_quot, gb_rem;
- unsigned long lba;
- lba = dev_desc->lba;
- lba512 = (lba * (dev_desc->blksz / 512));
- /* round to 1 digit */
- /* 2048 = (1024 * 1024) / 512 MB */
- mb = FSataBlockToMB(lba512, 10, 11);
- dev_desc->lba512 = lba512;
- FSATA_INFO("lba512=%lu, mb=%lu", lba512, mb);
- mb_quot = mb / 10;
- mb_rem = mb - (10 * mb_quot);
- gb = mb / 1024;
- gb_quot = gb / 10;
- gb_rem = gb - (10 * gb_quot);
- FSATA_INFO("Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)",
- mb_quot, mb_rem,
- gb_quot, gb_rem,
- (unsigned long)lba,
- dev_desc->blksz);
- }
- else
- {
- FSATA_INFO("Capacity: not available");
- }
- }
- /**
- * @name: FSataAhciReadCapacity
- * @msg: get sata capacity by parse instance_p ataid
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance.
- * @param {u8} port, port number
- * @param {unsigned long} *capacity, pointer to capacity value
- * @param {unsigned long} *blksz, pointer to block size
- * @return {FError} return FSATA_SUCCESS if successful, return others if failed
- */
- static FError FSataAhciReadCapacity(FSataCtrl *instance_p, u8 port,
- unsigned long *capacity, unsigned long *blksz)
- {
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- FError ret = FSATA_SUCCESS;
- u32 transfer_size; /* number of bytes per iteration */
- if (!instance_p->ataid[port])
- {
- FSATA_ERROR("READ CAPACITY10 command failure. "
- "\tNo ATA info!\n"
- "\tPlease run command INQUIRY first!");
- return FSATA_ERR_OPERATION;
- }
- u64 cap64 = FSataIdToSectors(instance_p->ataid[port]);
- if (cap64 > 0x100000000ULL)
- cap64 = 0xffffffff;
- *capacity = (unsigned long)(cap64);
- if (*capacity != 0xffffffff)
- {
- /* Read capacity (10) was sufficient for this drive. */
- *blksz = 512;
- return FSATA_SUCCESS;
- }
- else
- {
- FSATA_DEBUG("should read capacity 16?");
- }
- return FSATA_SUCCESS;
- }
- /**
- * @name: FSataAhciReadInfo
- * @msg: get sata information
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance.
- * @param {u8} port, port number
- * @return {FError} return FSATA_SUCCESS if read successful, return others if read failed
- */
- FError FSataAhciReadInfo(FSataCtrl *instance_p, u8 port)
- {
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- uintptr base_addr = instance_p->config.base_addr;
- FError ret = FSATA_SUCCESS;
- u16 *idbuf;
- unsigned long capacity, blksz;
- unsigned char info_data[50];
- memset(info_data, 0, sizeof(info_data));
- ret = FSataAhciInquiry(instance_p, port);
- if (ret != FSATA_SUCCESS)
- {
- FSATA_ERROR("FSataAhciInquiry!");
- return FSATA_ERR_OPERATION;
- }
- /* Parse SATA Information */
- idbuf = instance_p->ataid[port];
- FSataIdStrCopy((u16 *)&info_data[16], &idbuf[FSATA_ID_PROD], 16);
- FSataIdStrCopy((u16 *)&info_data[32], &idbuf[FSATA_ID_FW_REV], 4);
- /* is ata device */
- if (!((__swab16(idbuf[0]) & FSATA_ID_ATA_DEVICE)))
- {
- instance_p->port[port].dev_info.type = FSATA_DEV_TYPE_HARDDISK;
- memcpy(&info_data[8], "ATA ", 8); /* copy 8 bytes */
- }
- else
- {
- instance_p->port[port].dev_info.type = FSATA_DEV_TYPE_UNKNOWN;
- }
- /* get info for this device */
- FSataIdentityCopy((unsigned char *)instance_p->port[port].dev_info.vendor, &info_data[8], 8);
- FSataIdentityCopy((unsigned char *)instance_p->port[port].dev_info.product, &info_data[16], 16);
- FSataIdentityCopy((unsigned char *)instance_p->port[port].dev_info.revision, &info_data[32], 4);
- /* get sata capacity by parse ataid */
- ret = FSataAhciReadCapacity(instance_p, port, &capacity, &blksz);
- if (ret != FSATA_SUCCESS)
- {
- FSATA_ERROR("FSataAhciReadCapacity error!");
- return FSATA_ERR_OPERATION;
- }
- instance_p->port[port].dev_info.lba = capacity;
- instance_p->port[port].dev_info.blksz = blksz;
- instance_p->port[port].dev_info.if_type = FSATA_IF_TYPE_SCSI;
- FSataInfoPrint(&(instance_p->port[port].dev_info));
- return ret;
- }
- /**
- * @name: FSataAhciReset
- * @msg: reset ahci / hba(host bus adapter)
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance
- * @return {FError} return FSATA_SUCCESS if successful, return others if failed
- */
- static FError FSataAhciReset(FSataCtrl *instance_p)
- {
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- int i = WAIT_MS_RESET;
- uintptr base_addr = instance_p->config.base_addr;
- u32 reg_val = 0;
- /* read host control register and reset */
- reg_val = FSATA_READ_REG32(base_addr, FSATA_HOST_CTL);
- if ((reg_val & FSATA_HOST_RESET) == 0)
- {
- FSATA_SETBIT(base_addr, FSATA_HOST_CTL, FSATA_HOST_RESET);
- }
- /* reset must complete within 1 millisecond, or the hardware should be considered fried.*/
- do
- {
- fsleep_microsec(1000);
- reg_val = FSATA_READ_REG32(base_addr, FSATA_HOST_CTL);
- i--;
- }
- while ((i > 0) && (reg_val & FSATA_HOST_RESET));
- if (i == 0)
- {
- FSATA_ERROR("controller reset failed (0x%x)", reg_val);
- return FSATA_ERR_TIMEOUT;
- }
- return FSATA_SUCCESS;
- }
- /**
- * @name: FSataAhciInit
- * @msg: init ahci / hba(host bus adapter)
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance
- * @return {FError} return FSATA_SUCCESS if successful, return others if failed
- */
- FError FSataAhciInit(FSataCtrl *instance_p)
- {
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- uintptr base_addr = instance_p->config.base_addr;
- FError ret = FSATA_SUCCESS;
- u32 i;
- uintptr port_base_addr = 0; /* ahci port x base address */
- u32 reg_val = 0;
- u32 port_num = 0;
- /* reset host control */
- ret = FSataAhciReset(instance_p);
- if (ret != FSATA_SUCCESS)
- return ret;
- /* ahci enable */
- FSATA_WRITE_REG32(base_addr, FSATA_HOST_CTL, FSATA_HOST_AHCI_EN);
- FSATA_READ_REG32(base_addr, FSATA_HOST_CTL);
- /* read cap.np, set the ports bit which are available for software to use. */
- port_num = FSATA_READ_REG32(base_addr, FSATA_HOST_CAP) & FSATA_HOST_CAP_NP_MASK;
- FSATA_WRITE_REG32(base_addr, FSATA_HOST_PORTS_IMPL, FSATA_HOST_PORTS_IMPL_MASK(port_num));
- /* set instance_p paramameters */
- instance_p->n_ports = port_num + 1;
- instance_p->port_map = FSATA_READ_REG32(base_addr, FSATA_HOST_PORTS_IMPL);
- FSATA_DEBUG("port_map 0x%x n_ports %d", instance_p->port_map, instance_p->n_ports);
- for (i = 0; i < instance_p->n_ports; i++)
- {
- if (!(instance_p->port_map & BIT(i)))
- continue;
- /* set ports base address */
- instance_p->port[i].port_base_addr = FSataAhciPortBase(base_addr, i);
- port_base_addr = instance_p->port[i].port_base_addr;
- /* make sure port is not active */
- reg_val = FSATA_READ_REG32(port_base_addr, FSATA_PORT_CMD);
- if (reg_val & (FSATA_PORT_CMD_LIST_ON | FSATA_PORT_CMD_FIS_ON |
- FSATA_PORT_CMD_FIS_RX | FSATA_PORT_CMD_START))
- {
- FSATA_DEBUG("Port %d is active, reg = %#x. Deactivating.", i, reg_val);
- reg_val &= ~(FSATA_PORT_CMD_LIST_ON | FSATA_PORT_CMD_FIS_ON |
- FSATA_PORT_CMD_FIS_RX | FSATA_PORT_CMD_START);
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_CMD, reg_val);
- /* spec says 500 msecs for each bit, so this is slightly incorrect.*/
- fsleep_millisec(500);
- }
- /* Add the spinup command to whatever mode bits may
- * already be on in the command register, set not support staggered spin-up */
- reg_val = FSATA_READ_REG32(port_base_addr, FSATA_PORT_CMD);
- reg_val |= FSATA_PORT_CMD_SPIN_UP;
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_CMD, reg_val);
- /* check sata port is linked */
- ret = FSataAhciLinkUp(instance_p, i);
- if (ret)
- {
- FSATA_DEBUG("sata host %d, port %d link timeout", instance_p->config.instance_id, i);
- continue;
- }
- else
- {
- FSATA_DEBUG("sata host %d , port %d link ok.", instance_p->config.instance_id, i) ;
- }
- /* Clear error status */
- reg_val = FSATA_READ_REG32(port_base_addr, FSATA_PORT_SCR_ERR);
- if (reg_val)
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_SCR_ERR, reg_val);
- /* Device presence detected but Phy communication not established, retry once more */
- reg_val = FSATA_READ_REG32(port_base_addr, FSATA_PORT_SCR_STAT) & FSATA_PORT_SCR_STAT_DET_MASK;
- if (reg_val == FSATA_PORT_SCR_STAT_DET_COMINIT)
- {
- FSATA_INFO("sata link %d down, retrying...", i);
- i--;
- continue;
- }
- /* Clear error status */
- reg_val = FSATA_READ_REG32(port_base_addr, FSATA_PORT_SCR_ERR);
- if (reg_val)
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_SCR_ERR, reg_val);
- /* clear port irq status */
- reg_val = FSATA_READ_REG32(port_base_addr, FSATA_PORT_IRQ_STAT);
- if (reg_val)
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_IRQ_STAT, reg_val);
- /* clear host corresponding port interrupt status register */
- FSATA_WRITE_REG32(base_addr, FSATA_HOST_IRQ_STAT, BIT(i));
- /* register linkup ports */
- reg_val = FSATA_READ_REG32(port_base_addr, FSATA_PORT_SCR_STAT);
- if ((reg_val & FSATA_PORT_SCR_STAT_DET_MASK) == FSATA_PORT_SCR_STAT_DET_PHYRDY)
- instance_p->link_port_map |= BIT(i);
- }
- /* host interrupt enable */
- reg_val = FSATA_READ_REG32(base_addr, FSATA_HOST_CTL);
- FSATA_WRITE_REG32(base_addr, FSATA_HOST_CTL, reg_val | FSATA_HOST_IRQ_EN);
- return FSATA_SUCCESS;
- }
- /**
- * @name: FSataAhciPortStart
- * @msg: init ahci port, allocate Port Memory Usage
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance
- * @param {u8} port, port number
- * @param {uintptr} mem, Memory start address allocated to port
- * @return {FError} return FSATA_SUCCESS if successful, return others if failed
- */
- FError FSataAhciPortStart(FSataCtrl *instance_p, u8 port, uintptr mem)
- {
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- FASSERT(mem);
- uintptr base_addr = instance_p->config.base_addr;
- FError ret = FSATA_SUCCESS;
- FSataAhciPorts *port_info = &(instance_p->port[port]);
- uintptr port_base_addr = port_info->port_base_addr;
- u32 reg_val = FSATA_READ_REG32(port_base_addr, FSATA_PORT_SCR_STAT);
- if ((reg_val & FSATA_PORT_SCR_STAT_DET_MASK) != FSATA_PORT_SCR_STAT_DET_PHYRDY)
- {
- FSATA_ERROR("No Link on host %d port %d!", instance_p->config.instance_id, port);
- return FSATA_ERR_OPERATION;
- }
- memset((void *)mem, 0, FSATA_AHCI_PORT_PRIV_DMA_SZ);
- /* First item in chunk of DMA memory: 32 command lists, 32 bytes each in size */
- port_info->cmd_list = (FSataAhciCommandList *)(mem);
- mem += FSATA_AHCI_CMD_LIST_HEADER_SIZE * FSATA_AHCI_CMD_LIST_HEADER_NUM;
- /* Second item: Received-FIS area */
- port_info->rx_fis = (FSataAhciRecvFis *)(mem);
- mem += FSATA_AHCI_RX_FIS_SZ;
- /* Third item: data area for storing a single command and its scatter-gather table */
- port_info->cmd_tbl_base_addr = (uintptr)mem;
- mem += FSATA_AHCI_CMD_TABLE_HEADER_SIZE;
- /* command table prdt */
- port_info->cmd_tbl_prdt = (FSataAhciCommandTablePrdt *)mem;
- /* set ahci port registers */
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_LST_ADDR,
- (uintptr)port_info->cmd_list & FSATA_PORT_CMD_LIST_ADDR_MASK);
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_LST_ADDR_HI, 0);
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_FIS_ADDR,
- (uintptr)port_info->rx_fis & FSATA_PORT_CMD_FIS_ADDR_MASK);
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_FIS_ADDR_HI, 0);
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_CMD, FSATA_PORT_CMD_ICC_ACTIVE | FSATA_PORT_CMD_FIS_RX |
- FSATA_PORT_CMD_POWER_ON | FSATA_PORT_CMD_SPIN_UP | FSATA_PORT_CMD_START);
- /*
- * Make sure interface is not busy based on error and status
- * information from task file data register before proceeding
- */
- if (FSataWaitCmdCompleted(port_base_addr + FSATA_PORT_TFDATA, WAIT_MS_TFD, FSATA_BUSY))
- {
- FSATA_DEBUG("timeout exit!");
- return FSATA_ERR_TIMEOUT;
- }
- instance_p->private_data |= BIT(port);
- return ret;
- }
- /**
- * @name: FSataAhciFillCmdTablePrdt
- * @msg: allocate ahci command table prdt information
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance
- * @param {u8} port, port number
- * @param {unsigned char} *buffer, data buffer address
- * @param {int} buf_len, data length
- * @return {int} return item_count if successful, return -1 if failed
- */
- static int FSataAhciFillCmdTablePrdt(FSataCtrl *instance_p, u8 port,
- unsigned char *buf, int buf_len)
- {
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- FSataAhciPorts *port_info = &(instance_p->port[port]);
- FSataAhciCommandTablePrdt *command_table_prdt = port_info->cmd_tbl_prdt;
- int item_count;
- int i;
- item_count = ((buf_len - 1) / MAX_DATA_BYTE_COUNT) + 1;
- if (item_count > FSATA_AHCI_PRTD_ITEM_NUM)
- {
- FSATA_ERROR("Too much command table prdt items %d!", item_count);
- return -1;
- }
- for (i = 0; i < item_count; i++)
- {
- command_table_prdt->addr_low = ((unsigned long) buf + i * MAX_DATA_BYTE_COUNT);
- command_table_prdt->addr_high = 0;
- command_table_prdt->data_byte = (0x3fffff &
- (buf_len < MAX_DATA_BYTE_COUNT
- ? (buf_len - 1)
- : (MAX_DATA_BYTE_COUNT - 1)));
- command_table_prdt++;
- buf_len -= MAX_DATA_BYTE_COUNT;
- }
- return item_count;
- }
- /**
- * @name: FSataAhciFillCmdList
- * @msg: allocate ahci command list information
- * @param {FSataAhciPorts} *port_info is a pointer to the FSataAhciPorts instance
- * @param {u32} description_info, prdtl+flag+cfl
- * @return {void}
- */
- static void FSataAhciFillCmdList(FSataAhciPorts *port_info, u32 description_info)
- {
- FASSERT(port_info != NULL);
- port_info->cmd_list->description_info = description_info;
- port_info->cmd_list->status = 0;
- port_info->cmd_list->tbl_addr = ((u32)port_info->cmd_tbl_base_addr & FSATA_PORT_CMD_TABLE_ADDR_MASK);
- #ifdef __aarch64__
- port_info->cmd_list->tbl_addr_hi = (u32)(((port_info->cmd_tbl_base_addr) >> 16) >> 16);
- #endif
- }
- /**
- * @name: FSataAhciDataIO
- * @msg: transfer ahci command fis and data buffer
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance
- * @param {u8} port number
- * @param {u8} *fis, command fis buffer
- * @param {int} fis_len, command fis length
- * @param {u8} *buf, data read/write buffer
- * @param {int} buf_len, data length
- * @param {u8} is_write, 0-read, 1-write
- * @return {FError} return FSATA_SUCCESS if successful, return others if failed
- */
- static FError FSataAhciDataIO(FSataCtrl *instance_p, u8 port, u8 *fis,
- int fis_len, u8 *buf, int buf_len, boolean is_ncq, boolean is_write)
- {
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- FASSERT(fis != NULL);
- FSataAhciPorts *port_info = &(instance_p->port[port]);
- uintptr base_addr = instance_p->config.base_addr;
- uintptr port_base_addr = instance_p->port[port].port_base_addr;
- if (port >= instance_p->n_ports)
- {
- FSATA_DEBUG("Invalid port number %d", port);
- return FSATA_ERR_INVAILD_PARAMETER;
- }
- u32 reg_val = FSATA_READ_REG32(port_base_addr, FSATA_PORT_SCR_STAT);
- if ((reg_val & FSATA_PORT_SCR_STAT_DET_MASK) != FSATA_PORT_SCR_STAT_DET_PHYRDY)
- {
- FSATA_ERROR("No Link on host %d port %d!", instance_p->config.instance_id, port);
- return FSATA_ERR_OPERATION;
- }
- /* copy fis command to command table CFIS */
- memcpy((unsigned char *)port_info->cmd_tbl_base_addr, fis, fis_len);
- /* copy data buffer address to command table prdt item */
- int prdt_length = FSataAhciFillCmdTablePrdt(instance_p, port, buf, buf_len);
- if (prdt_length == -1)
- {
- FSATA_ERROR("FSataAhciFillCmdTablePrdt failed, buf_len = %d\n", buf_len);
- return FSATA_ERR_INVAILD_PARAMETER;
- }
- /* command list DW0: PRDTL(buf len) + W/R + CFL(fis len, 4 Byte(Dword) aligned) */
- u32 description_info = (prdt_length << 16) | (is_write << 6) | (fis_len >> 2);
- /* copy data to command list struct */
- FSataAhciFillCmdList(port_info, description_info);
- FCacheDCacheFlushRange((unsigned long)port_info->cmd_list, FSATA_AHCI_PORT_PRIV_DMA_SZ);
- FCacheDCacheFlushRange((unsigned long)buf, (unsigned long)buf_len);
- /* set tag bit in SACT register before write CI register when use native cmd */
- if (is_ncq == TRUE)
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_SCR_ACT, FSATA_PORT_SCR_ACT_ENABLE);
- /* send cmd */
- FSATA_WRITE_REG32(port_base_addr, FSATA_PORT_CMD_ISSUE, FSATA_PORT_CMD_ISSUE_ENABLE);
- if (FSataWaitCmdCompleted(port_base_addr + FSATA_PORT_CMD_ISSUE, WAIT_MS_DATAIO, FSATA_PORT_CMD_ISSUE_ENABLE))
- {
- FSATA_ERROR("timeout exit!");
- return FSATA_ERR_TIMEOUT;
- }
- return FSATA_SUCCESS;
- }
- /**
- * @name: FSataReadWrite
- * @msg: read or write sata block data, choose if use ncq
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance
- * @param {u8} port, port number
- * @param {u32} start, start block
- * @param {u32} blk_cnt, block count
- * @param {u8} *buffer, data buffer
- * @param {boolean} is_ncq, FALSE-not support ncq, TRUE-support ncq
- * @param {boolean} is_write, read or write, FALSE-read, TRUE-write
- * @return {FError} return FSATA_SUCCESS if successful, return others if failed
- */
- FError FSataReadWrite(FSataCtrl *instance_p, u8 port, u32 start,
- u16 blk_cnt, u8 *buffer, boolean is_ncq, boolean is_write)
- {
- FASSERT(instance_p != NULL);
- FASSERT(instance_p->is_ready == FT_COMPONENT_IS_READY);
- FASSERT(blk_cnt);
- uintptr base_addr = instance_p->config.base_addr;
- FError ret = FSATA_SUCCESS;
- u16 now_blocks; /* number of blocks per iteration */
- u32 transfer_size; /* number of bytes per iteration */
- u8 fis[20];
- /* Preset the FIS */
- memset(fis, 0, sizeof(fis));
- fis[0] = FSATA_FIS_REG_HOST_TO_DEVICE;/* fis type */
- fis[1] = FSATA_FIS_REG_HOST_TO_DEVICE_C; /* C and PM Port */
- if (is_ncq == FALSE)
- fis[2] = is_write ? FSATA_CMD_WRITE_EXT : FSATA_CMD_READ_EXT; /* Command */
- else
- fis[2] = is_write ? FSATA_CMD_FPDMA_WRITE : FSATA_CMD_FPDMA_READ; /* Command */
- while (blk_cnt)
- {
- now_blocks = min((u16)MAX_SATA_BLOCKS_READ_WRITE, blk_cnt);
- transfer_size = FSATA_SECT_SIZE * now_blocks;
- if (is_ncq == FALSE)
- {
- /* FEATURE Reserved */
- fis[3] = 0; /* features 7:0 */
- fis[11] = 0; /* features 15:8 */
- /* LBA of first logical sector to be transferred */
- fis[4] = ((start >> 0) & 0xff); /* lba 7:0 */
- fis[5] = ((start >> 8) & 0xff); /* lba 15:8 */
- fis[6] = ((start >> 16) & 0xff); /* lba 23:16 */
- fis[8] = ((start >> 24) & 0xff); /* lba 31:24 */
- /* device reg, bit 6 Shall be set to one in read command */
- fis[7] = FSATA_CMD_EXT_DEVICE;
- /* The number of logical sectors to be transferred. */
- fis[12] = (now_blocks >> 0) & 0xff;/* count 7:0 */
- fis[13] = (now_blocks >> 8) & 0xff;/* count 15:8 */
- }
- else
- {
- /* FEATURE:The number of logical sectors to be transferred. */
- fis[3] = (now_blocks >> 0) & 0xff; /* features 7:0 */
- fis[11] = (now_blocks >> 8) & 0xff; /* features 15:8 */
- /* LBA of first logical sector to be transferred */
- fis[4] = ((start >> 0) & 0xff); /* lba 7:0 */
- fis[5] = ((start >> 8) & 0xff); /* lba 15:8 */
- fis[6] = ((start >> 16) & 0xff); /* lba 23:16 */
- fis[8] = ((start >> 24) & 0xff); /* lba 31:24 */
- /* device reg, bit 6 Shall be set to one */
- fis[7] = FSATA_CMD_EXT_DEVICE;
- /* count */
- fis[12] = 0;/* count 7:0, NCQ TAG field */
- fis[13] = 0;/* count 15:8, Normal priority */
- }
- ret = FSataAhciDataIO(instance_p, port, fis, sizeof(fis),
- buffer, transfer_size, is_ncq, is_write);
- if (ret)
- {
- FSATA_ERROR("scsi_ahci: SCSI command failure. ret = %#x", ret);
- return FSATA_ERR_OPERATION;
- }
- buffer += transfer_size;
- blk_cnt -= now_blocks;
- start += now_blocks;
- }
- return ret;
- }
- /**
- * @name: FSataCfgInitialize
- * @msg: Initialize Sata ctrl
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance.
- * @param {FSataConfig} *input_config_p, Default configuration parameters of FSata
- * @return {FError} return FSATA_SUCCESS if successful, return others if failed
- */
- FError FSataCfgInitialize(FSataCtrl *instance_p, const FSataConfig *input_config_p)
- {
- FASSERT(instance_p);
- /*Set default values and configuration data */
- FSataCfgDeInitialize(instance_p);
- instance_p->config = *input_config_p;
- instance_p->is_ready = FT_COMPONENT_IS_READY;
- return FSATA_SUCCESS;
- }
- /**
- * @name: FSataCfgDeInitialize
- * @msg: DeInitialization function for the device instance
- * @param {FSataCtrl} *instance_p, pointer to the FSataCtrl instance.
- * @return {*}
- */
- void FSataCfgDeInitialize(FSataCtrl *pctrl)
- {
- FASSERT(pctrl);
- pctrl->is_ready = 0;
- memset(pctrl, 0, sizeof(*pctrl));
- return;
- }
|