/*============================================================================= Copyright (C) 2016 Kristina Brooks All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 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 GNU General Public License for more details. FILE DESCRIPTION SDHOST driver. This used to be known as ALTMMC. =============================================================================*/ #include #include #include "sd2.hpp" #define SDEDM_WRITE_THRESHOLD_SHIFT 9 #define SDEDM_READ_THRESHOLD_SHIFT 14 #define SDEDM_THRESHOLD_MASK 0x1f #define SAFE_READ_THRESHOLD 4 #define SAFE_WRITE_THRESHOLD 4 #define VOLTAGE_SUPPLY_RANGE 0x100 #define CHECK_PATTERN 0x55 #define SDHSTS_BUSY_IRPT 0x400 #define SDHSTS_BLOCK_IRPT 0x200 #define SDHSTS_SDIO_IRPT 0x100 #define SDHSTS_REW_TIME_OUT 0x80 #define SDHSTS_CMD_TIME_OUT 0x40 #define SDHSTS_CRC16_ERROR 0x20 #define SDHSTS_CRC7_ERROR 0x10 #define SDHSTS_FIFO_ERROR 0x08 #define SDHSTS_TRANSFER_ERROR_MASK (SDHSTS_CRC7_ERROR|SDHSTS_CRC16_ERROR|SDHSTS_REW_TIME_OUT|SDHSTS_FIFO_ERROR) #define SDHSTS_ERROR_MASK (SDHSTS_CMD_TIME_OUT|SDHSTS_TRANSFER_ERROR_MASK) #define logf(fmt, ...) printf("[sdhost::%s]: " fmt, __FUNCTION__, ##__VA_ARGS__); struct sdhost_t { bool is_sdhc; bool is_high_capacity; uint32_t ocr; uint32_t rca; uint32_t cid[4]; uint32_t csd[4]; uint32_t r[4]; void set_power(bool on) { SH_VDD = on ? SH_VDD_POWER_ON_SET : 0x0; } bool wait(uint32_t timeout = 10000) { uint32_t t = timeout; while(SH_CMD & SH_CMD_NEW_FLAG_SET) { if (t == 0) { logf("timed out after %dus!\n", timeout) return false; } t--; udelay(10); } return true; } bool send_raw(uint32_t command, uint32_t arg = 0) { uint32_t sts; wait(); sts = SH_HSTS; if (sts & SDHSTS_ERROR_MASK) SH_HSTS = sts; SH_ARG = arg; SH_CMD = command | SH_CMD_NEW_FLAG_SET; mfence(); return true; } bool send(uint32_t command, uint32_t arg = 0) { return send_raw(command & SH_CMD_COMMAND_SET, arg); } void configure_pinmux() { GP_FSEL4 = 0x24000000; GP_FSEL5 = 0x924; GP_PUD = 2; logf("GPIOs set!\n"); } void reset() { logf("resetting controller ...\n"); set_power(false); SH_CMD = 0; SH_ARG = 0; SH_TOUT = 0xF00000; SH_CDIV = 0; SH_HSTS = 0x7f8; SH_HCFG = 0; SH_HBCT = 0; SH_HBLC = 0; uint32_t temp = SH_EDM; temp &= ~((SDEDM_THRESHOLD_MASK<