diff --git a/board/longanpi-3h/smhc_test/main.c b/board/longanpi-3h/smhc_test/main.c index 94223a61..edb084cf 100644 --- a/board/longanpi-3h/smhc_test/main.c +++ b/board/longanpi-3h/smhc_test/main.c @@ -25,6 +25,21 @@ extern sunxi_i2c_t i2c_pmu; extern void set_cpu_poweroff(void); +void set_pmu_fin_voltage(char* power_name, uint32_t voltage){ + int set_vol = voltage; + int temp_vol, src_vol = pmu_axp1530_get_vol(&i2c_pmu, power_name); + if (src_vol > voltage) { + for (temp_vol = src_vol; temp_vol >= voltage; temp_vol -= 50) { + pmu_axp1530_set_vol(&i2c_pmu, power_name, temp_vol, 1); + } + } else if (src_vol < voltage) { + for (temp_vol = src_vol; temp_vol <= voltage; temp_vol += 50) { + pmu_axp1530_set_vol(&i2c_pmu, power_name, temp_vol, 1); + } + } + mdelay(30); /* Delay 300ms for pmu bootup */ +} + int main(void) { sunxi_serial_init(&uart_dbg); @@ -42,20 +57,8 @@ int main(void) { pmu_axp1530_dump(&i2c_pmu); - int set_vol = 1100; /* LPDDR4 1100mv */ - - int temp_vol, src_vol = pmu_axp1530_get_vol(&i2c_pmu, "dcdc3"); - if (src_vol > set_vol) { - for (temp_vol = src_vol; temp_vol >= set_vol; temp_vol -= 50) { - pmu_axp1530_set_vol(&i2c_pmu, "dcdc3", temp_vol, 1); - } - } else if (src_vol < set_vol) { - for (temp_vol = src_vol; temp_vol <= set_vol; temp_vol += 50) { - pmu_axp1530_set_vol(&i2c_pmu, "dcdc3", temp_vol, 1); - } - } - - mdelay(30); /* Delay 300ms for pmu bootup */ + set_pmu_fin_voltage("dcdc2", 1100); + set_pmu_fin_voltage("dcdc3", 1100); pmu_axp1530_dump(&i2c_pmu); @@ -67,9 +70,16 @@ int main(void) { if (sunxi_sdhci_init(&sdhci0) != 0) { printk(LOG_LEVEL_ERROR, "SMHC: %s controller init failed\n", sdhci0.name); } else { - printk(LOG_LEVEL_INFO, "SMHC: %s controller v%x initialized\n", sdhci0.name, sdhci0.reg->vers); + printk(LOG_LEVEL_INFO, "SMHC: %s controller initialized\n", sdhci0.name); } + /* Initialize the SD card and check if initialization is successful. */ + if (sdmmc_init(&card0, &sdhci0) != 0) { + printk(LOG_LEVEL_WARNING, "SMHC: init failed\n"); + } + + printk(LOG_LEVEL_DEBUG, "Card OK!\n"); + abort(); return 0; diff --git a/include/drivers/sun50iw9/reg/reg-smhc.h b/include/drivers/sun50iw9/reg/reg-smhc.h new file mode 100644 index 00000000..81131842 --- /dev/null +++ b/include/drivers/sun50iw9/reg/reg-smhc.h @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#ifndef __REG_SMHC_H__ +#define __REG_SMHC_H__ + +/* + * Global control register bits + */ +#define SMHC_GCTRL_SOFT_RESET (1 << 0) +#define SMHC_GCTRL_FIFO_RESET (1 << 1) +#define SMHC_GCTRL_DMA_RESET (1 << 2) +#define SMHC_GCTRL_INTERRUPT_ENABLE (1 << 4) +#define SMHC_GCTRL_DMA_ENABLE (1 << 5) +#define SMHC_GCTRL_DEBOUNCE_ENABLE (1 << 8) +#define SMHC_GCTRL_POSEDGE_LATCH_DATA (1 << 9) +#define SMHC_GCTRL_DDR_MODE (1 << 10) +#define SMHC_GCTRL_MEMORY_ACCESS_DONE (1 << 29) +#define SMHC_GCTRL_ACCESS_DONE_DIRECT (1 << 30) +#define SMHC_GCTRL_ACCESS_BY_AHB (1 << 31) +#define SMHC_GCTRL_ACCESS_BY_DMA (0 << 31) +#define SMHC_GCTRL_HARDWARE_RESET \ + (SMHC_GCTRL_SOFT_RESET | SMHC_GCTRL_FIFO_RESET | SMHC_GCTRL_DMA_RESET) + +/* + * Clock control bits + */ +#define SMHC_CLKCR_MASK_D0 (1 << 31) +#define SMHC_CLKCR_CARD_CLOCK_ON (1 << 16) +#define SMHC_CLKCR_LOW_POWER_ON (1 << 17) +#define SMHC_CLKCR_CLOCK_DIV(n) ((n - 1) & 0xff) + +/* + * Bus width + */ +#define SMHC_WIDTH_1BIT (0) +#define SMHC_WIDTH_4BIT (1) + +/* + * Smc command bits + */ +#define SMHC_CMD_RESP_EXPIRE (1 << 6) +#define SMHC_CMD_LONG_RESPONSE (1 << 7) +#define SMHC_CMD_CHECK_RESPONSE_CRC (1 << 8) +#define SMHC_CMD_DATA_EXPIRE (1 << 9) +#define SMHC_CMD_WRITE (1 << 10) +#define SMHC_CMD_SEQUENCE_MODE (1 << 11) +#define SMHC_CMD_SEND_AUTO_STOP (1 << 12) +#define SMHC_CMD_WAIT_PRE_OVER (1 << 13) +#define SMHC_CMD_STOP_ABORT_CMD (1 << 14) +#define SMHC_CMD_SEND_INIT_SEQUENCE (1 << 15) +#define SMHC_CMD_UPCLK_ONLY (1 << 21) +#define SMHC_CMD_READ_CEATA_DEV (1 << 22) +#define SMHC_CMD_CCS_EXPIRE (1 << 23) +#define SMHC_CMD_ENABLE_BIT_BOOT (1 << 24) +#define SMHC_CMD_ALT_BOOT_OPTIONS (1 << 25) +#define SMHC_CMD_BOOT_ACK_EXPIRE (1 << 26) +#define SMHC_CMD_BOOT_ABORT (1 << 27) +#define SMHC_CMD_VOLTAGE_SWITCH (1 << 28) +#define SMHC_CMD_USE_HOLD_REGISTER (1 << 29) +#define SMHC_CMD_START (1 << 31) + +/* + * Interrupt bits + */ +#define SMHC_RINT_RESP_ERROR (0x1 << 1) +#define SMHC_RINT_COMMAND_DONE (0x1 << 2) +#define SMHC_RINT_DATA_OVER (0x1 << 3) +#define SMHC_RINT_TX_DATA_REQUEST (0x1 << 4) +#define SMHC_RINT_RX_DATA_REQUEST (0x1 << 5) +#define SMHC_RINT_RESP_CRC_ERROR (0x1 << 6) +#define SMHC_RINT_DATA_CRC_ERROR (0x1 << 7) +#define SMHC_RINT_RESP_TIMEOUT (0x1 << 8) +#define SMHC_RINT_DATA_TIMEOUT (0x1 << 9) +#define SMHC_RINT_VOLTAGE_CHANGE_DONE (0x1 << 10) +#define SMHC_RINT_FIFO_RUN_ERROR (0x1 << 11) +#define SMHC_RINT_HARD_WARE_LOCKED (0x1 << 12) +#define SMHC_RINT_START_BIT_ERROR (0x1 << 13) +#define SMHC_RINT_AUTO_COMMAND_DONE (0x1 << 14) +#define SMHC_RINT_END_BIT_ERROR (0x1 << 15) +#define SMHC_RINT_SDIO_INTERRUPT (0x1 << 16) +#define SMHC_RINT_CARD_INSERT (0x1 << 30) +#define SMHC_RINT_CARD_REMOVE (0x1 << 31) +#define SMHC_RINT_INTERRUPT_ERROR_BIT \ + (SMHC_RINT_RESP_ERROR | SMHC_RINT_RESP_CRC_ERROR | \ + SMHC_RINT_DATA_CRC_ERROR | SMHC_RINT_RESP_TIMEOUT | \ + SMHC_RINT_DATA_TIMEOUT | SMHC_RINT_VOLTAGE_CHANGE_DONE | \ + SMHC_RINT_FIFO_RUN_ERROR | SMHC_RINT_HARD_WARE_LOCKED | \ + SMHC_RINT_START_BIT_ERROR | SMHC_RINT_END_BIT_ERROR) /* 0xbfc2 */ +#define SMHC_RINT_INTERRUPT_DONE_BIT \ + (SMHC_RINT_AUTO_COMMAND_DONE | SMHC_RINT_DATA_OVER | \ + SMHC_RINT_COMMAND_DONE | SMHC_RINT_VOLTAGE_CHANGE_DONE) + +/* + * Status + */ +#define SMHC_STATUS_RXWL_FLAG (1 << 0) +#define SMHC_STATUS_TXWL_FLAG (1 << 1) +#define SMHC_STATUS_FIFO_EMPTY (1 << 2) +#define SMHC_STATUS_FIFO_FULL (1 << 3) +#define SMHC_STATUS_CARD_PRESENT (1 << 8) +#define SMHC_STATUS_CARD_DATA_BUSY (1 << 9) +#define SMHC_STATUS_DATA_FSM_BUSY (1 << 10) +#define SMHC_STATUS_DMA_REQUEST (1 << 31) +#define SMHC_STATUS_FIFO_SIZE (16) +#define SMHC_STATUS_FIFO_LEVEL(x) (((x) >> 17) & 0x3fff) + +/* IDMA controller bus mod bit field */ +#define SMHC_IDMAC_SOFT_RESET BIT(0) +#define SMHC_IDMAC_FIX_BURST BIT(1) +#define SMHC_IDMAC_IDMA_ON BIT(7) +#define SMHC_IDMAC_REFETCH_DES BIT(31) + +/* IDMA status bit field */ +#define SMHC_IDMAC_TRANSMIT_INTERRUPT BIT(0) +#define SMHC_IDMAC_RECEIVE_INTERRUPT BIT(1) +#define SMHC_IDMAC_FATAL_BUS_ERROR BIT(2) +#define SMHC_IDMAC_DESTINATION_INVALID BIT(4) +#define SMHC_IDMAC_CARD_ERROR_SUM BIT(5) +#define SMHC_IDMAC_NORMAL_INTERRUPT_SUM BIT(8) +#define SMHC_IDMAC_ABNORMAL_INTERRUPT_SUM BIT(9) +#define SMHC_IDMAC_HOST_ABORT_INTERRUPT BIT(10) +#define SMHC_IDMAC_IDLE (0 << 13) +#define SMHC_IDMAC_SUSPEND (1 << 13) +#define SMHC_IDMAC_DESC_READ (2 << 13) +#define SMHC_IDMAC_DESC_CHECK (3 << 13) +#define SMHC_IDMAC_READ_REQUEST_WAIT (4 << 13) +#define SMHC_IDMAC_WRITE_REQUEST_WAIT (5 << 13) +#define SMHC_IDMAC_READ (6 << 13) +#define SMHC_IDMAC_WRITE (7 << 13) +#define SMHC_IDMAC_DESC_CLOSE (8 << 13) + +/* + * If the idma-des-size-bits of property is ie 13, bufsize bits are: + * Bits 0-12: buf1 size + * Bits 13-25: buf2 size + * Bits 26-31: not used + * Since we only ever set buf1 size, we can simply store it directly. + */ +#define SMHC_IDMAC_DES0_DIC BIT(1) /* disable interrupt on completion */ +#define SMHC_IDMAC_DES0_LD BIT(2) /* last descriptor */ +#define SMHC_IDMAC_DES0_FD BIT(3) /* first descriptor */ +#define SMHC_IDMAC_DES0_CH BIT(4) /* chain mode */ +#define SMHC_IDMAC_DES0_ER BIT(5) /* end of ring */ +#define SMHC_IDMAC_DES0_CES BIT(30) /* card error summary */ +#define SMHC_IDMAC_DES0_OWN BIT(31) /* 1-idma owns it, 0-host owns it */ + +/* +timing mode +0: output and input are both based on [0,1,...,7] pll delay. +1: output and input are both based on phase. +2: output is based on phase, input is based on delay chain except hs400. + input of hs400 is based on delay chain. +3: output is based on phase, input is based on delay chain. +4: output is based on phase, input is based on delay chain. + it also support to use delay chain on data strobe signal. +*/ +#define SUNXI_MMC_TIMING_MODE_0 0U +#define SUNXI_MMC_TIMING_MODE_1 1U +#define SUNXI_MMC_TIMING_MODE_2 2U +#define SUNXI_MMC_TIMING_MODE_3 3U +#define SUNXI_MMC_TIMING_MODE_4 4U +#define SUNXI_MMC_TIMING_MODE_5 5U + +#define MMC_CLK_SAMPLE_POINIT_MODE_0 8U +#define MMC_CLK_SAMPLE_POINIT_MODE_1 3U +#define MMC_CLK_SAMPLE_POINIT_MODE_2 2U +#define MMC_CLK_SAMPLE_POINIT_MODE_2_HS400 64U +#define MMC_CLK_SAMPLE_POINIT_MODE_3 64U +#define MMC_CLK_SAMPLE_POINIT_MODE_4 64U +#define MMC_CLK_SAMPLE_POINIT_MODE_5 64U + +#define TM5_OUT_PH90 (0) +#define TM5_OUT_PH180 (1) +#define TM5_IN_PH90 (0) +#define TM5_IN_PH180 (1) +#define TM5_IN_PH270 (2) +#define TM5_IN_PH0 (3) + +/* delay control */ +#define SDXC_NTDC_START_CAL (1 << 15) +#define SDXC_NTDC_CAL_DONE (1 << 14) +#define SDXC_NTDC_CAL_DLY (0x3F << 8) +#define SDXC_NTDC_ENABLE_DLY (1 << 7) +#define SDXC_NTDC_CFG_DLY (0x3F << 0) +#define SDXC_NTDC_CFG_NEW_DLY (0xF << 0) + +#define DTO_MAX 200 +#define SUNXI_MMC_NTSR_MODE_SEL_NEW (0x1 << 31) + +typedef struct { + volatile uint32_t gctrl; /* (0x00) SMC Global Control Register */ + volatile uint32_t clkcr; /* (0x04) SMC Clock Control Register */ + volatile uint32_t timeout; /* (0x08) SMC Time Out Register */ + volatile uint32_t width; /* (0x0C) SMC Bus Width Register */ + volatile uint32_t blksz; /* (0x10) SMC Block Size Register */ + volatile uint32_t bytecnt; /* (0x14) SMC Byte Count Register */ + volatile uint32_t cmd; /* (0x18) SMC Command Register */ + volatile uint32_t arg; /* (0x1C) SMC Argument Register */ + volatile uint32_t resp0; /* (0x20) SMC Response Register 0 */ + volatile uint32_t resp1; /* (0x24) SMC Response Register 1 */ + volatile uint32_t resp2; /* (0x28) SMC Response Register 2 */ + volatile uint32_t resp3; /* (0x2C) SMC Response Register 3 */ + volatile uint32_t imask; /* (0x30) SMC Interrupt Mask Register */ + volatile uint32_t mint; /* (0x34) SMC Masked Interrupt Status Register */ + volatile uint32_t rint; /* (0x38) SMC Raw Interrupt Status Register */ + volatile uint32_t status; /* (0x3C) SMC Status Register */ + volatile uint32_t ftrglevel; /* (0x40) SMC FIFO Threshold Watermark Register */ + volatile uint32_t funcsel; /* (0x44) SMC Function Select Register */ + volatile uint32_t cbcr; /* (0x48) SMC CIU Byte Count Register */ + volatile uint32_t bbcr; /* (0x4C) SMC BIU Byte Count Register */ + volatile uint32_t dbgc; /* (0x50) SMC Debug Enable Register */ + volatile uint32_t csdc; /* (0x54) CRC status detect control register*/ + volatile uint32_t a12a; /* (0x58)Auto command 12 argument*/ + volatile uint32_t ntsr; /* (0x5c)SMC2 Newtiming Set Register */ + volatile uint32_t res1[6]; /* (0x54~0x74) */ + volatile uint32_t hwrst; /* (0x78) SMC eMMC Hardware Reset Register */ + volatile uint32_t res2; /* (0x7c) */ + volatile uint32_t dmac; /* (0x80) SMC IDMAC Control Register */ + volatile uint32_t dlba; /* (0x84) SMC IDMAC Descriptor List Base Address Register */ + volatile uint32_t idst; /* (0x88) SMC IDMAC Status Register */ + volatile uint32_t idie; /* (0x8C) SMC IDMAC Interrupt Enable Register */ + volatile uint32_t chda; /* (0x90) */ + volatile uint32_t cbda; /* (0x94) */ + volatile uint32_t res3[26]; /* (0x98~0xff) */ + volatile uint32_t thldc; /* (0x100) Card Threshold Control Register */ + volatile uint32_t sfc; /* 0x104 SMC Sample FIFO Control Register */ + volatile uint32_t res4[1]; /* 0x108 */ + volatile uint32_t dsbd; /* (0x10c) eMMC4.5 DDR Start Bit Detection Control */ + volatile uint32_t res5[12]; /* (0x110~0x13c) */ + volatile uint32_t drv_dl; /* (0x140) drive delay control register*/ + volatile uint32_t samp_dl; /* (0x144) sample delay control register*/ + volatile uint32_t ds_dl; /* (0x148) data strobe delay control register */ + volatile uint32_t res6[45]; /* (0x110~0x1ff) */ + volatile uint32_t fifo; /* (0x200) SMC FIFO Access Address */ +} sdhci_reg_t; + +#endif// __REG_SMHC_H__ \ No newline at end of file diff --git a/include/drivers/sun50iw9/sys-sdhci.h b/include/drivers/sun50iw9/sys-sdhci.h new file mode 100644 index 00000000..30be93e0 --- /dev/null +++ b/include/drivers/sun50iw9/sys-sdhci.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#ifndef __SDHCI_H__ +#define __SDHCI_H__ + +#include +#include +#include +#include +#include +#include + +#include "reg/reg-smhc.h" +#include "sys-gpio.h" + +#include "log.h" + +typedef enum { + MMC_CLK_400K = 0, + MMC_CLK_25M = 1, + MMC_CLK_50M = 2, + MMC_CLK_50M_DDR = 3, + MMC_CLK_100M = 4, + MMC_CLK_150M = 5, + MMC_CLK_200M = 6 +} smhc_clk_t; + +typedef struct { + uint32_t idx; + uint32_t arg; + uint32_t resptype; + uint32_t response[4]; +} sdhci_cmd_t; + +typedef struct { + uint8_t *buf; + uint32_t flag; + uint32_t blksz; + uint32_t blkcnt; +} sdhci_data_t; + +#define SMHC_DES_NUM_SHIFT 12 /* smhc2!! */ +#define SMHC_DES_BUFFER_MAX_LEN (1 << SMHC_DES_NUM_SHIFT) +typedef struct { + uint32_t : 1, dic : 1, /* disable interrupt on completion */ + last_desc : 1, /* 1-this data buffer is the last buffer */ + first_desc : 1, /* 1-data buffer is the first buffer, 0-data buffer contained in the next descriptor is 1st + buffer */ + des_chain : 1, /* 1-the 2nd address in the descriptor is the next descriptor address */ + // end_of_ring : 1, /* 1-last descriptor flag when using dual data buffer in descriptor */ + : 25, err_flag : 1, /* transfer error flag */ + own : 1; /* des owner:1-idma owns it, 0-host owns it */ + + uint32_t data_buf_sz : SMHC_DES_NUM_SHIFT, + data_buf_dummy : (32 - SMHC_DES_NUM_SHIFT); + + uint32_t buf_addr; + uint32_t next_desc_addr; + +} sdhci_idma_desc_t __attribute__((aligned(8))); + +typedef struct { + char *name; + sdhci_reg_t *reg; + uint32_t reset; + + uint32_t voltage; + uint32_t width; + smhc_clk_t clock; + uint32_t pclk; + volatile uint8_t odly[6]; + volatile uint8_t sdly[6]; + + volatile sdhci_idma_desc_t dma_desc[32]; + uint32_t dma_trglvl; + + bool removable; + bool isspi; + + gpio_mux_t gpio_d0; + gpio_mux_t gpio_d1; + gpio_mux_t gpio_d2; + gpio_mux_t gpio_d3; + gpio_mux_t gpio_cmd; + gpio_mux_t gpio_clk; +} sdhci_t; + +extern sdhci_t sdhci0; + +bool sdhci_reset(sdhci_t *hci); +bool sdhci_set_voltage(sdhci_t *hci, uint32_t voltage); +bool sdhci_set_width(sdhci_t *hci, uint32_t width); +bool sdhci_set_clock(sdhci_t *hci, smhc_clk_t hz); +bool sdhci_transfer(sdhci_t *hci, sdhci_cmd_t *cmd, sdhci_data_t *dat); +int sunxi_sdhci_init(sdhci_t *sdhci); + +#endif /* __SDHCI_H__ */ diff --git a/include/drivers/sun8iw20/reg/reg-smhc.h b/include/drivers/sun8iw20/reg/reg-smhc.h index 37d97d68..3e190279 100644 --- a/include/drivers/sun8iw20/reg/reg-smhc.h +++ b/include/drivers/sun8iw20/reg/reg-smhc.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ -#ifndef __G_REG_SMHC_H__ -#define __G_REG_SMHC_H__ +#ifndef __REG_SMHC_H__ +#define __REG_SMHC_H__ /* * Global control register bits @@ -260,4 +260,4 @@ typedef struct { volatile uint32_t vers; /* (0x300) SMHC Version Register */ } sdhci_reg_t; -#endif // __G_REG_SMHC_H__ \ No newline at end of file +#endif // __REG_SMHC_H__ \ No newline at end of file diff --git a/include/drivers/sun8iw21/reg/reg-smhc.h b/include/drivers/sun8iw21/reg/reg-smhc.h index 37d97d68..3e190279 100644 --- a/include/drivers/sun8iw21/reg/reg-smhc.h +++ b/include/drivers/sun8iw21/reg/reg-smhc.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: Apache-2.0 */ -#ifndef __G_REG_SMHC_H__ -#define __G_REG_SMHC_H__ +#ifndef __REG_SMHC_H__ +#define __REG_SMHC_H__ /* * Global control register bits @@ -260,4 +260,4 @@ typedef struct { volatile uint32_t vers; /* (0x300) SMHC Version Register */ } sdhci_reg_t; -#endif // __G_REG_SMHC_H__ \ No newline at end of file +#endif // __REG_SMHC_H__ \ No newline at end of file diff --git a/include/drivers/sys-sdhci.h b/include/drivers/sys-sdhci.h index 9e27e4e1..ee159c39 100644 --- a/include/drivers/sys-sdhci.h +++ b/include/drivers/sys-sdhci.h @@ -7,6 +7,8 @@ #include #elif defined(CONFIG_CHIP_SUN8IW20) #include +#elif defined(CONFIG_CHIP_SUN50IW9) + #include #else # error "Unsupported chip" #endif diff --git a/src/drivers/pmu/axp1530.c b/src/drivers/pmu/axp1530.c index 25cee3ab..cdbc9397 100644 --- a/src/drivers/pmu/axp1530.c +++ b/src/drivers/pmu/axp1530.c @@ -74,13 +74,7 @@ int pmu_axp1530_init(sunxi_i2c_t *i2c_dev) { printk(LOG_LEVEL_INFO, "PMU: Cannot found match PMU\n"); return -1; } - /* Set DCDC2 GPU voltage to 1.16V */ - if (sunxi_i2c_read(i2c_dev, AXP1530_RUNTIME_ADDR, AXP1530_DC2OUT_VOL, &axp_val)) - return -1; - axp_val |= (0x1 << 7); - if (sunxi_i2c_write(i2c_dev, AXP1530_RUNTIME_ADDR, AXP1530_DC2OUT_VOL, axp_val)) - return -1; - + /* Set over temperature shutdown functtion */ if (sunxi_i2c_read(i2c_dev, AXP1530_RUNTIME_ADDR, AXP1530_POWER_DOMN_SEQUENCE, &axp_val)) return -1; diff --git a/src/drivers/sun50iw9/CMakeLists.txt b/src/drivers/sun50iw9/CMakeLists.txt index 85ef8974..37dffc97 100644 --- a/src/drivers/sun50iw9/CMakeLists.txt +++ b/src/drivers/sun50iw9/CMakeLists.txt @@ -5,4 +5,5 @@ add_library(chip_drivers-obj OBJECT sys-dram.c sys-sid.c sys-wdt.c + sys-sdhci.c ) \ No newline at end of file diff --git a/src/drivers/sun50iw9/sys-sdhci.c b/src/drivers/sun50iw9/sys-sdhci.c new file mode 100644 index 00000000..3d03e96f --- /dev/null +++ b/src/drivers/sun50iw9/sys-sdhci.c @@ -0,0 +1,627 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "sys-sdcard.h" +#include "sys-sdhci.h" + +#define FALSE 0 +#define TRUE 1 + +static void set_read_timeout(sdhci_t *sdhci, uint32_t timeout) { + uint32_t rval = 0; + uint32_t rdto_clk = 0; + uint32_t mode_2x = 0; + + rdto_clk = sdhci->clock / 1000 * timeout; + rval = sdhci->reg->ntsr; + mode_2x = rval & (0x1 << 31); + + if ((sdhci->clock == MMC_CLK_50M_DDR && mode_2x)) { + rdto_clk = rdto_clk << 1; + } + + rval = sdhci->reg->gctrl; + /*ddr50 mode don't use 256x timeout unit*/ + if (rdto_clk > 0xffffff && sdhci->clock == MMC_CLK_50M_DDR) { + rdto_clk = (rdto_clk + 255) / 256; + rval |= (0x1 << 11); + } else { + rdto_clk = 0xffffff; + rval &= ~(0x1 << 11); + } + sdhci->reg->gctrl = rval; + + rval = sdhci->reg->timeout; + rval &= ~(0xffffff << 8); + rval |= (rdto_clk << 8); + sdhci->reg->timeout = rval; + + printk(LOG_LEVEL_TRACE, + "rdtoclk:%u, reg-tmout:%u, gctl:%x, clock:%u, nstr:%x\n", + rdto_clk, sdhci->reg->timeout, sdhci->reg->gctrl, sdhci->clock, + sdhci->reg->ntsr); +} + +static int prepare_dma(sdhci_t *sdhci, sdhci_data_t *data) { + sdhci_idma_desc_t *pdes = sdhci->dma_desc; + uint32_t byte_cnt = data->blksz * data->blkcnt; + uint8_t *buff; + uint32_t des_idx = 0; + uint32_t buff_frag_num = 0; + uint32_t remain; + uint32_t i; + + buff = data->buf; + buff_frag_num = byte_cnt >> SMHC_DES_NUM_SHIFT; + remain = byte_cnt & (SMHC_DES_BUFFER_MAX_LEN - 1); + if (remain) + buff_frag_num++; + else + remain = SMHC_DES_BUFFER_MAX_LEN - 1; + + for (i = 0; i < buff_frag_num; i++, des_idx++) { + memset((void *) &pdes[des_idx], 0, sizeof(sdhci_idma_desc_t)); + pdes[des_idx].des_chain = 1; + pdes[des_idx].own = 1; + pdes[des_idx].dic = 1; + if (buff_frag_num > 1 && i != buff_frag_num - 1) + pdes[des_idx].data_buf_sz = SMHC_DES_BUFFER_MAX_LEN - 1; + else + pdes[des_idx].data_buf_sz = remain; + pdes[des_idx].buf_addr = + ((uint32_t) buff + i * SMHC_DES_BUFFER_MAX_LEN) >> 2; + if (i == 0) + pdes[des_idx].first_desc = 1; + + if (i == buff_frag_num - 1) { + pdes[des_idx].dic = 0; + pdes[des_idx].last_desc = 1; + pdes[des_idx].next_desc_addr = 0; + } else { + pdes[des_idx].next_desc_addr = + ((uint32_t) &pdes[des_idx + 1]) >> 2; + } + printk(LOG_LEVEL_TRACE, + "SMHC: frag %d, remain %d, des[%d] = 0x%08x:\n" + " [0] = 0x%08x, [1] = 0x%08x, [2] = 0x%08x, [3] = 0x%08x\n", + i, remain, des_idx, (uint32_t) (&pdes[des_idx]), + (uint32_t) ((uint32_t *) &pdes[des_idx])[0], + (uint32_t) ((uint32_t *) &pdes[des_idx])[1], + (uint32_t) ((uint32_t *) &pdes[des_idx])[2], + (uint32_t) ((uint32_t *) &pdes[des_idx])[3]); + } + + wmb(); + + /* + * GCTRLREG + * GCTRL[2] : DMA reset + * GCTRL[5] : DMA enable + * + * IDMACREG + * IDMAC[0] : IDMA soft reset + * IDMAC[1] : IDMA fix burst flag + * IDMAC[7] : IDMA on + * + * IDIECREG + * IDIE[0] : IDMA transmit interrupt flag + * IDIE[1] : IDMA receive interrupt flag + */ + sdhci->reg->idst = 0x337;// clear interrupt status + sdhci->reg->gctrl |= SMHC_GCTRL_DMA_ENABLE | + SMHC_GCTRL_DMA_RESET; /* dma enable */ + sdhci->reg->dmac = SMHC_IDMAC_SOFT_RESET; /* idma reset */ + while (sdhci->reg->dmac & SMHC_IDMAC_SOFT_RESET) + ; + + sdhci->reg->dmac = SMHC_IDMAC_FIX_BURST | + SMHC_IDMAC_IDMA_ON; /* idma on */ + sdhci->reg->idie &= + ~(SMHC_IDMAC_TRANSMIT_INTERRUPT | SMHC_IDMAC_RECEIVE_INTERRUPT); + if (data->flag & MMC_DATA_WRITE) + sdhci->reg->idie |= SMHC_IDMAC_TRANSMIT_INTERRUPT; + else + sdhci->reg->idie |= SMHC_IDMAC_RECEIVE_INTERRUPT; + + sdhci->reg->dlba = (uint32_t) pdes >> 2; + sdhci->reg->ftrglevel = sdhci->dma_trglvl; + + return 0; +} + +static int wait_done(sdhci_t *sdhci, sdhci_data_t *dat, uint32_t timeout_msecs, + uint32_t flag, bool dma) { + uint32_t status; + uint32_t done = 0; + uint32_t start = time_ms(); + printk(LOG_LEVEL_TRACE, "SMHC: wait for flag 0x%x\n", flag); + do { + status = sdhci->reg->rint; + if ((time_ms() > (start + timeout_msecs))) { + printk(LOG_LEVEL_WARNING, + "SMHC: wait timeout %x status %x flag %x\n", + status & SMHC_RINT_INTERRUPT_ERROR_BIT, status, + flag); + return -1; + } else if ((status & SMHC_RINT_INTERRUPT_ERROR_BIT)) { + printk(LOG_LEVEL_WARNING, + "SMHC: error 0x%x status 0x%x\n", + status & SMHC_RINT_INTERRUPT_ERROR_BIT, + status & ~SMHC_RINT_INTERRUPT_ERROR_BIT); + return -1; + } + if (dat && dma && (dat->blkcnt * dat->blksz) > 0) + done = ((status & flag) && + (sdhci->reg->idst & + SMHC_IDMAC_RECEIVE_INTERRUPT)) + ? 1 + : 0; + else + done = (status & flag); + } while (!done); + + return 0; +} + +static bool read_bytes(sdhci_t *sdhci, sdhci_data_t *dat) { + uint32_t count = dat->blkcnt * dat->blksz; + uint32_t *tmp = (uint32_t *) dat->buf; + uint32_t status, err, done; + uint32_t timeout = time_ms() + count; + uint32_t in_fifo; + + if (timeout < 250) + timeout = 250; + + printk(LOG_LEVEL_TRACE, "SMHC: read %u\n", count); + + status = sdhci->reg->status; + err = sdhci->reg->rint & SMHC_RINT_INTERRUPT_ERROR_BIT; + if (err) + printk(LOG_LEVEL_WARNING, + "SMHC: interrupt error 0x%x status 0x%x\n", + err & SMHC_RINT_INTERRUPT_ERROR_BIT, status); + + while ((!err) && (count >= sizeof(sdhci->reg->fifo))) { + while (sdhci->reg->status & SMHC_STATUS_FIFO_EMPTY) { + if (time_ms() > timeout) { + printk(LOG_LEVEL_WARNING, + "SMHC: read timeout\n"); + return FALSE; + } + } + in_fifo = SMHC_STATUS_FIFO_LEVEL(status); + count -= sizeof(sdhci->reg->fifo) * in_fifo; + while (in_fifo--) { + *(tmp++) = sdhci->reg->fifo; + } + + status = sdhci->reg->status; + err = sdhci->reg->rint & SMHC_RINT_INTERRUPT_ERROR_BIT; + } + + do { + status = sdhci->reg->rint; + + err = status & SMHC_RINT_INTERRUPT_ERROR_BIT; + if (dat->blkcnt > 1) + done = status & SMHC_RINT_AUTO_COMMAND_DONE; + else + done = status & SMHC_RINT_DATA_OVER; + + } while (!done && !err); + + if (err & SMHC_RINT_INTERRUPT_ERROR_BIT) { + printk(LOG_LEVEL_WARNING, + "SMHC: interrupt error 0x%x status 0x%x\n", + err & SMHC_RINT_INTERRUPT_ERROR_BIT, status); + return FALSE; + } + + if (count) { + printk(LOG_LEVEL_WARNING, "SMHC: read %u leftover\n", count); + return FALSE; + } + return TRUE; +} + +static bool write_bytes(sdhci_t *sdhci, sdhci_data_t *dat) { + uint64_t count = dat->blkcnt * dat->blksz; + uint32_t *tmp = (uint32_t *) dat->buf; + uint32_t status, err, done; + uint32_t timeout = time_ms() + count; + + if (timeout < 250) + timeout = 250; + + printk(LOG_LEVEL_TRACE, "SMHC: write %u\n", count); + + status = sdhci->reg->status; + err = sdhci->reg->rint & SMHC_RINT_INTERRUPT_ERROR_BIT; + while (!err && count) { + while (sdhci->reg->status & SMHC_STATUS_FIFO_FULL) { + if (time_ms() > timeout) { + printk(LOG_LEVEL_WARNING, + "SMHC: write timeout\n"); + return FALSE; + } + } + sdhci->reg->fifo = *(tmp++); + count -= sizeof(uint32_t); + + status = sdhci->reg->status; + err = sdhci->reg->rint & SMHC_RINT_INTERRUPT_ERROR_BIT; + } + + do { + status = sdhci->reg->rint; + err = status & SMHC_RINT_INTERRUPT_ERROR_BIT; + if (dat->blkcnt > 1) + done = status & SMHC_RINT_AUTO_COMMAND_DONE; + else + done = status & SMHC_RINT_DATA_OVER; + } while (!done && !err); + + if (err & SMHC_RINT_INTERRUPT_ERROR_BIT) + return FALSE; + + if (count) + return FALSE; + return TRUE; +} + +bool sdhci_transfer(sdhci_t *sdhci, sdhci_cmd_t *cmd, sdhci_data_t *dat) { + uint32_t cmdval = 0; + uint32_t status = 0; + uint32_t timeout; + bool dma = false; + + printk(LOG_LEVEL_TRACE, "SMHC: CMD%u 0x%x dlen:%u\n", cmd->idx, + cmd->arg, dat ? dat->blkcnt * dat->blksz : 0); + + if (cmd->idx == MMC_STOP_TRANSMISSION) { + timeout = time_ms(); + do { + status = sdhci->reg->status; + if (time_ms() - timeout > 10) { + sdhci->reg->gctrl = SMHC_GCTRL_HARDWARE_RESET; + sdhci->reg->rint = 0xffffffff; + printk(LOG_LEVEL_WARNING, + "SMHC: stop timeout\n"); + return FALSE; + } + } while (status & SMHC_STATUS_CARD_DATA_BUSY); + return TRUE; + } + + if (cmd->resptype & MMC_RSP_PRESENT) { + cmdval |= SMHC_CMD_RESP_EXPIRE; + if (cmd->resptype & MMC_RSP_136) + cmdval |= SMHC_CMD_LONG_RESPONSE; + if (cmd->resptype & MMC_RSP_CRC) + cmdval |= SMHC_CMD_CHECK_RESPONSE_CRC; + } + + if (dat) { + sdhci->reg->blksz = dat->blksz; + sdhci->reg->bytecnt = (uint32_t) (dat->blkcnt * dat->blksz); + + cmdval |= SMHC_CMD_DATA_EXPIRE | SMHC_CMD_WAIT_PRE_OVER; + set_read_timeout(sdhci, DTO_MAX); + + if (dat->flag & MMC_DATA_WRITE) { + cmdval |= SMHC_CMD_WRITE; + sdhci->reg->idst |= + SMHC_IDMAC_TRANSMIT_INTERRUPT;// clear TX status + } + if (dat->flag & MMC_DATA_READ) + sdhci->reg->idst |= + SMHC_IDMAC_RECEIVE_INTERRUPT;// clear RX status + } + + if (cmd->idx == MMC_WRITE_MULTIPLE_BLOCK || + cmd->idx == MMC_READ_MULTIPLE_BLOCK) + cmdval |= SMHC_CMD_SEND_AUTO_STOP; + + sdhci->reg->rint = 0xffffffff;// Clear status + sdhci->reg->arg = cmd->arg; + + if (dat && (dat->blkcnt * dat->blksz) > 64) { + dma = true; + sdhci->reg->gctrl &= ~SMHC_GCTRL_ACCESS_BY_AHB; + prepare_dma(sdhci, dat); + sdhci->reg->cmd = cmdval | cmd->idx | SMHC_CMD_START;// Start + } else if (dat && (dat->blkcnt * dat->blksz) > 0) { + sdhci->reg->gctrl |= SMHC_GCTRL_ACCESS_BY_AHB; + sdhci->reg->cmd = cmdval | cmd->idx | SMHC_CMD_START;// Start + if (dat->flag & MMC_DATA_READ && !read_bytes(sdhci, dat)) + return FALSE; + else if (dat->flag & MMC_DATA_WRITE && !write_bytes(sdhci, dat)) + return FALSE; + } else { + sdhci->reg->gctrl |= SMHC_GCTRL_ACCESS_BY_AHB; + sdhci->reg->cmd = cmdval | cmd->idx | SMHC_CMD_START;// Start + } + + if (wait_done(sdhci, 0, 100, SMHC_RINT_COMMAND_DONE, false)) { + printk(LOG_LEVEL_WARNING, "SMHC: cmd timeout\n"); + return FALSE; + } + + if (dat && wait_done(sdhci, dat, 6000, + dat->blkcnt > 1 ? SMHC_RINT_AUTO_COMMAND_DONE : SMHC_RINT_DATA_OVER, + dma)) { + printk(LOG_LEVEL_WARNING, "SMHC: data timeout\n"); + return FALSE; + } + + if (cmd->resptype & MMC_RSP_BUSY) { + timeout = time_ms(); + do { + status = sdhci->reg->status; + if (time_ms() - timeout > 10) { + sdhci->reg->gctrl = SMHC_GCTRL_HARDWARE_RESET; + sdhci->reg->rint = 0xffffffff; + printk(LOG_LEVEL_WARNING, + "SMHC: busy timeout\n"); + return FALSE; + } + } while (status & SMHC_STATUS_CARD_DATA_BUSY); + } + + if (cmd->resptype & MMC_RSP_136) { + cmd->response[0] = sdhci->reg->resp3; + cmd->response[1] = sdhci->reg->resp2; + cmd->response[2] = sdhci->reg->resp1; + cmd->response[3] = sdhci->reg->resp0; + } else { + cmd->response[0] = sdhci->reg->resp0; + } + + // Cleanup and disable IDMA + if (dat && dma) { + status = sdhci->reg->idst; + sdhci->reg->idst = status; + sdhci->reg->idie = 0; + sdhci->reg->dmac = 0; + sdhci->reg->gctrl &= ~SMHC_GCTRL_DMA_ENABLE; + } + + return TRUE; +} + +bool sdhci_reset(sdhci_t *sdhci) { + sdhci->reg->gctrl = SMHC_GCTRL_HARDWARE_RESET; + return TRUE; +} + +bool sdhci_set_width(sdhci_t *sdhci, uint32_t width) { + const char *mode = "1 bit"; + sdhci->reg->gctrl &= ~SMHC_GCTRL_DDR_MODE; + switch (width) { + case MMC_BUS_WIDTH_1: + sdhci->reg->width = SMHC_WIDTH_1BIT; + break; + case MMC_BUS_WIDTH_4: + sdhci->reg->width = SMHC_WIDTH_4BIT; + mode = "4 bit"; + break; + default: + printk(LOG_LEVEL_ERROR, "SMHC: %u width value invalid\n", + width); + return FALSE; + } + if (sdhci->clock == MMC_CLK_50M_DDR) { + sdhci->reg->gctrl |= SMHC_GCTRL_DDR_MODE; + mode = "4 bit DDR"; + } + + printk(LOG_LEVEL_TRACE, "SMHC: set width to %s\n", mode); + return TRUE; +} + +static int config_delay(sdhci_t *sdhci) { + uint32_t rval, freq, val; + uint8_t odly, sdly; + + freq = sdhci->clock; + + odly = sdhci->odly[freq]; + sdly = sdhci->sdly[freq]; + + printk(LOG_LEVEL_TRACE, "SMHC: odly: %d sldy: %d\n", odly, sdly); + + val = read32(CCU_BASE + CCU_SMHC0_CLK_REG); + val &= (~CCU_MMC_CTRL_ENABLE); + write32(CCU_BASE + CCU_SMHC0_CLK_REG, val); + + sdhci->reg->drv_dl &= (~(0x3 << 16)); + sdhci->reg->drv_dl |= (((odly & 0x1) << 16) | ((odly & 0x1) << 17)); + + val = read32(CCU_BASE + CCU_SMHC0_CLK_REG); + val |= CCU_MMC_CTRL_ENABLE; + write32(CCU_BASE + CCU_SMHC0_CLK_REG, val); + + rval = sdhci->reg->ntsr; + rval &= (~(0x3 << 8)); + rval |= ((sdly & 0x3) << 8); + sdhci->reg->ntsr = rval; + + return 0; +} + +static bool update_card_clock(sdhci_t *sdhci) { + sdhci->reg->cmd = SMHC_CMD_START | SMHC_CMD_UPCLK_ONLY | + SMHC_CMD_WAIT_PRE_OVER; + uint32_t timeout = time_ms(); + + do { + if (time_ms() - timeout > 10) + return FALSE; + } while (sdhci->reg->cmd & SMHC_CMD_START); + + sdhci->reg->rint = 0xffffffff; + return TRUE; +} + +bool sdhci_set_clock(sdhci_t *sdhci, smhc_clk_t clock) { + uint32_t div, n, mod_hz, pll, pll_hz, hz, val; + + switch (clock) { + case MMC_CLK_400K: + hz = 400000; + break; + case MMC_CLK_25M: + hz = 25000000; + break; + case MMC_CLK_50M: + case MMC_CLK_50M_DDR: + hz = 50000000; + break; + case MMC_CLK_100M: + hz = 100000000; + break; + case MMC_CLK_150M: + hz = 150000000; + break; + case MMC_CLK_200M: + hz = 200000000; + break; + default: + printk(LOG_LEVEL_ERROR, "SHMC: invalid clock: %u\n", clock); + return false; + } + + if (hz < 1000000) { + printk(LOG_LEVEL_TRACE, "SMHC: set clock to %.2fKHz\n", + (f32) ((f32) hz / 1000.0)); + } else { + printk(LOG_LEVEL_TRACE, "SMHC: set clock to %.2fMHz\n", + (f32) ((f32) hz / 1000000.0)); + } + + if (sdhci->clock == MMC_CLK_50M_DDR) + mod_hz = hz * 4; /* 4xclk: DDR 4(HS); */ + else + mod_hz = hz * 2; /* 2xclk: SDR 1/4; */ + + if (mod_hz <= 24000000) { + pll = CCU_MMC_CTRL_OSCM24; + pll_hz = 24000000; + } else { + pll = CCU_MMC_CTRL_PLL_PERIPH1X; + pll_hz = sunxi_clk_get_peri1x_rate(); + } + + div = pll_hz / mod_hz; + if (pll_hz % mod_hz) + div++; + + n = 0; + while (div > 16) { + n++; + div = (div + 1) / 2; + } + + if (n > 3) { + printk(LOG_LEVEL_ERROR, "mmc %u error cannot set clock to %uHz\n", sdhci->name, hz); + return false; + } + + printk(LOG_LEVEL_TRACE, "SMHC: clock ratio %u\n", div); + + sdhci->reg->clkcr &= ~SMHC_CLKCR_CARD_CLOCK_ON;// Disable clock + if (!update_card_clock(sdhci)) + return false; + + sdhci->reg->ntsr |= SUNXI_MMC_NTSR_MODE_SEL_NEW; + + val = read32(CCU_BASE + CCU_SMHC_BGR_REG); + val |= CCU_MMC_BGR_SMHC0_RST; + write32(CCU_BASE + CCU_SMHC_BGR_REG, val); + + val = read32(CCU_BASE + CCU_SMHC0_CLK_REG); + val &= (~CCU_MMC_CTRL_ENABLE); + write32(CCU_BASE + CCU_SMHC0_CLK_REG, val); + + val = read32(CCU_BASE + CCU_SMHC0_CLK_REG); + val = pll | CCU_MMC_CTRL_N(n) | CCU_MMC_CTRL_M(div); + write32(CCU_BASE + CCU_SMHC0_CLK_REG, val); + + val = read32(CCU_BASE + CCU_SMHC0_CLK_REG); + val |= CCU_MMC_CTRL_ENABLE; + write32(CCU_BASE + CCU_SMHC0_CLK_REG, val); + + val = read32(CCU_BASE + CCU_SMHC_BGR_REG); + val |= CCU_MMC_BGR_SMHC0_GATE; + write32(CCU_BASE + CCU_SMHC_BGR_REG, val); + + sdhci->pclk = mod_hz; + + sdhci->reg->clkcr |= SMHC_CLKCR_MASK_D0;// Mask D0 when updating + sdhci->reg->clkcr &= ~(0xff); // Clear div (set to 1) + if (sdhci->clock == MMC_CLK_50M_DDR) { + sdhci->reg->clkcr |= SMHC_CLKCR_CLOCK_DIV(2); + } + sdhci->reg->clkcr |= SMHC_CLKCR_CARD_CLOCK_ON;// Enable clock + + if (!update_card_clock(sdhci)) + return false; + + config_delay(sdhci); + + return true; +} + +static int init_default_timing(sdhci_t *sdhci) { + sdhci->odly[MMC_CLK_400K] = TM5_OUT_PH180; + sdhci->odly[MMC_CLK_25M] = TM5_OUT_PH180; + sdhci->odly[MMC_CLK_50M] = TM5_OUT_PH180; + sdhci->odly[MMC_CLK_50M_DDR] = TM5_OUT_PH90; + + sdhci->sdly[MMC_CLK_400K] = TM5_IN_PH180; + sdhci->sdly[MMC_CLK_25M] = TM5_IN_PH180; + sdhci->sdly[MMC_CLK_50M] = TM5_IN_PH90; + sdhci->sdly[MMC_CLK_50M_DDR] = TM5_IN_PH180; + return 0; +} + +int sunxi_sdhci_init(sdhci_t *sdhci) { + sunxi_gpio_init(sdhci->gpio_clk.pin, sdhci->gpio_clk.mux); + sunxi_gpio_set_pull(sdhci->gpio_clk.pin, GPIO_PULL_UP); + + sunxi_gpio_init(sdhci->gpio_cmd.pin, sdhci->gpio_cmd.mux); + sunxi_gpio_set_pull(sdhci->gpio_cmd.pin, GPIO_PULL_UP); + + sunxi_gpio_init(sdhci->gpio_d0.pin, sdhci->gpio_d0.mux); + sunxi_gpio_set_pull(sdhci->gpio_d0.pin, GPIO_PULL_UP); + + sunxi_gpio_init(sdhci->gpio_d1.pin, sdhci->gpio_d1.mux); + sunxi_gpio_set_pull(sdhci->gpio_d1.pin, GPIO_PULL_UP); + + sunxi_gpio_init(sdhci->gpio_d2.pin, sdhci->gpio_d2.mux); + sunxi_gpio_set_pull(sdhci->gpio_d2.pin, GPIO_PULL_UP); + + sunxi_gpio_init(sdhci->gpio_d3.pin, sdhci->gpio_d3.mux); + sunxi_gpio_set_pull(sdhci->gpio_d3.pin, GPIO_PULL_UP); + + init_default_timing(sdhci); + sdhci_set_clock(sdhci, MMC_CLK_400K); + + udelay(100); + + return 0; +} diff --git a/src/drivers/sun8iw21/sys-sdhci.c b/src/drivers/sun8iw21/sys-sdhci.c index 025d12bd..3384c577 100644 --- a/src/drivers/sun8iw21/sys-sdhci.c +++ b/src/drivers/sun8iw21/sys-sdhci.c @@ -8,8 +8,8 @@ #include #include -#include #include +#include #include #include @@ -558,9 +558,7 @@ bool sdhci_set_clock(sdhci_t *sdhci, smhc_clk_t clock) { } if (n > 3) { - printk(LOG_LEVEL_ERROR, - "mmc %u error cannot set clock to %uHz\n", sdhci->name, - hz); + printk(LOG_LEVEL_ERROR, "mmc %u error cannot set clock to %uHz\n", sdhci->name, hz); return false; }