imx95-a55-evk: add USDHC eMMC driver support

Port USDHC1 (eMMC) driver to the i.MX95 FRDM EVK board:
- Create imx95_pinmux.h with SD1/USDHC1 pin definitions
- Add USDHC1 pin macros to board.h
- Create board-level imx9_usdhc.c glue code
- Update imx9_bringup.c with DMA allocator and USDHC init
- Add SCMI clock guards in imx9_usdhc.c (imx95 clock roots
  are owned by System Manager, direct CCM writes are no-ops)
- Fix CCM_CR_USDHC2 copy-paste bug to CCM_CR_USDHC1

Signed-off-by: buxiasen <buxiasen@xiaomi.com>
This commit is contained in:
buxiasen
2026-03-06 15:51:12 +08:00
committed by Xiang Xiao
parent 695774a940
commit 0b75df277d
13 changed files with 1213 additions and 14 deletions
+3
View File
@@ -202,6 +202,9 @@ choice
depends on IMX9_USDHC2
prompt "Bus width for USDHC2"
default IMX9_USDHC2_WIDTH_D1_D4
---help---
USDHC2 supports up to 4-bit data width only according to chip
spec. No 8-bit option is provided.
config IMX9_USDHC2_WIDTH_D1_ONLY
bool "One bit"
@@ -104,12 +104,12 @@
/* DRAMPLL registers */
#define DRAMPLL_CTRL (IMX9_AUDIOPLL_BASE + PLL_CTRL_OFFSET)
#define DRAMPLL_SPREAD_SPECTRUM (IMX9_AUDIOPLL_BASE + PLL_SPREAD_SPECTRUM_OFFSET)
#define DRAMPLL_NUMERATOR (IMX9_AUDIOPLL_BASE + PLL_NUMERATOR_OFFSET)
#define DRAMPLL_DENOMINATOR (IMX9_AUDIOPLL_BASE + PLL_DENOMINATOR_OFFSET)
#define DRAMPLL_DIV (IMX9_AUDIOPLL_BASE + PLL_DIV_OFFSET)
#define DRAMPLL_PLL_STATUS (IMX9_AUDIOPLL_BASE + PLL_PLL_STATUS_OFFSET)
#define DRAMPLL_CTRL (IMX9_DRAMPLL_BASE + PLL_CTRL_OFFSET)
#define DRAMPLL_SPREAD_SPECTRUM (IMX9_DRAMPLL_BASE + PLL_SPREAD_SPECTRUM_OFFSET)
#define DRAMPLL_NUMERATOR (IMX9_DRAMPLL_BASE + PLL_NUMERATOR_OFFSET)
#define DRAMPLL_DENOMINATOR (IMX9_DRAMPLL_BASE + PLL_DENOMINATOR_OFFSET)
#define DRAMPLL_DIV (IMX9_DRAMPLL_BASE + PLL_DIV_OFFSET)
#define DRAMPLL_PLL_STATUS (IMX9_DRAMPLL_BASE + PLL_PLL_STATUS_OFFSET)
/* VIDEOPLL registers */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,50 @@
/****************************************************************************
* arch/arm64/src/imx9/hardware/imx95/imx95_pinmux.h
*
* SPDX-License-Identifier: Apache-2.0
* SPDX-FileCopyrightText: 2024 NXP
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX95_IMX95_PINMUX_H
#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX95_IMX95_PINMUX_H
/* SD1 / USDHC1 pin configurations (ALT0, no daisy chain)
*
* IOMUX_PADCFG(mux_ctl_reg, mux_mode, daisy_reg, daisy_val, pad_ctl_reg)
*
* Addresses: IMX9_IOMUXC1_BASE (0x443c0000) + offset
* MUX_CTL: SD1_CLK=0x0128, SD1_CMD=0x012c, SD1_DATA0-7=0x0130-0x014c,
* SD1_STROBE=0x0150
* PAD_CTL: SD1_CLK=0x032c, SD1_CMD=0x0330, SD1_DATA0-7=0x0334-0x0350,
* SD1_STROBE=0x0354
*/
#define IOMUXC_PAD_SD1_CLK_USDHC1_CLK IOMUX_PADCFG(0x443c0128, 0x0, 0x00000000, 0x00000000, 0x443c032c)
#define IOMUXC_PAD_SD1_CMD_USDHC1_CMD IOMUX_PADCFG(0x443c012c, 0x0, 0x00000000, 0x00000000, 0x443c0330)
#define IOMUXC_PAD_SD1_DATA0_USDHC1_DATA0 IOMUX_PADCFG(0x443c0130, 0x0, 0x00000000, 0x00000000, 0x443c0334)
#define IOMUXC_PAD_SD1_DATA1_USDHC1_DATA1 IOMUX_PADCFG(0x443c0134, 0x0, 0x00000000, 0x00000000, 0x443c0338)
#define IOMUXC_PAD_SD1_DATA2_USDHC1_DATA2 IOMUX_PADCFG(0x443c0138, 0x0, 0x00000000, 0x00000000, 0x443c033c)
#define IOMUXC_PAD_SD1_DATA3_USDHC1_DATA3 IOMUX_PADCFG(0x443c013c, 0x0, 0x00000000, 0x00000000, 0x443c0340)
#define IOMUXC_PAD_SD1_DATA4_USDHC1_DATA4 IOMUX_PADCFG(0x443c0140, 0x0, 0x00000000, 0x00000000, 0x443c0344)
#define IOMUXC_PAD_SD1_DATA5_USDHC1_DATA5 IOMUX_PADCFG(0x443c0144, 0x0, 0x00000000, 0x00000000, 0x443c0348)
#define IOMUXC_PAD_SD1_DATA6_USDHC1_DATA6 IOMUX_PADCFG(0x443c0148, 0x0, 0x00000000, 0x00000000, 0x443c034c)
#define IOMUXC_PAD_SD1_DATA7_USDHC1_DATA7 IOMUX_PADCFG(0x443c014c, 0x0, 0x00000000, 0x00000000, 0x443c0350)
#define IOMUXC_PAD_SD1_STROBE_USDHC1_STROBE IOMUX_PADCFG(0x443c0150, 0x0, 0x00000000, 0x00000000, 0x443c0354)
#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX95_IMX95_PINMUX_H */
@@ -0,0 +1,197 @@
/****************************************************************************
* arch/arm64/src/imx9/hardware/imx95/imx95_pll.h
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX95_IMX95_PLL_H
#define __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX95_IMX95_PLL_H
/* All registers besides STATUS have SET, CLR, TGL and VAL shadow registers */
#define PLL_REG_VAL_OFFSET (0x00)
#define PLL_REG_SET_OFFSET (0x04)
#define PLL_REG_CLR_OFFSET (0x08)
#define PLL_REG_TGL_OFFSET (0x0c)
/* User can access the individual registers via these macros */
#define PLL_VAL(n) ((n) + PLL_REG_VAL_OFFSET) /* Same as the register itself */
#define PLL_SET(n) ((n) + PLL_REG_SET_OFFSET)
#define PLL_CLR(n) ((n) + PLL_REG_CLR_OFFSET)
#define PLL_TGL(n) ((n) + PLL_REG_TGL_OFFSET)
/* Common offsets for all PLL registers, existence depends on the register
* itself
*/
#define PLL_CTRL_OFFSET (0x00) /* PLL Control */
#define PLL_SPREAD_SPECTRUM_OFFSET (0x30) /* Spread Spectrum */
#define PLL_NUMERATOR_OFFSET (0x40) /* Numerator */
#define PLL_DENOMINATOR_OFFSET (0x50) /* Denominator */
#define PLL_DIV_OFFSET (0x60) /* PLL Dividers */
#define PLL_DFS_CTRL_0_OFFSET (0x70) /* DFS Control */
#define PLL_DFS_DIV_0_OFFSET (0x80) /* DFS Division_0 */
#define PLL_DFS_CTRL_1_OFFSET (0x90) /* DFS Control */
#define PLL_DFS_DIV_1_OFFSET (0xa0) /* DFS Division_1 */
#define PLL_DFS_CTRL_2_OFFSET (0xb0) /* DFS Control */
#define PLL_DFS_DIV_2_OFFSET (0xc0) /* DFS Division_2 */
#define PLL_PLL_STATUS_OFFSET (0xf0) /* PLL Status */
#define PLL_DFS_STATUS_OFFSET (0xf4) /* DFS Status */
/* Register addresses */
#define PLL_CTRL(n) ((n) + PLL_CTRL_OFFSET)
#define PLL_SPREAD_SPECTRUM(n) ((n) + PLL_SPREAD_SPECTRUM_OFFSET)
#define PLL_NUMERATOR(n) ((n) + PLL_NUMERATOR_OFFSET)
#define PLL_DENOMINATOR(n) ((n) + PLL_DENOMINATOR_OFFSET)
#define PLL_DIV(n) ((n) + PLL_DIV_OFFSET)
#define PLL_DFS_CTRL_0(n) ((n) + PLL_DFS_CTRL_0_OFFSET)
#define PLL_DFS_DIV_0(n) ((n) + PLL_DFS_DIV_0_OFFSET)
#define PLL_DFS_CTRL_1(n) ((n) + PLL_DFS_CTRL_1_OFFSET)
#define PLL_DFS_DIV_1(n) ((n) + PLL_DFS_DIV_1_OFFSET)
#define PLL_DFS_CTRL_2(n) ((n) + PLL_DFS_CTRL_2_OFFSET)
#define PLL_DFS_DIV_2(n) ((n) + PLL_DFS_DIV_2_OFFSET)
#define PLL_PLL_STATUS(n) ((n) + PLL_PLL_STATUS_OFFSET)
#define PLL_DFS_STATUS(n) ((n) + PLL_DFS_STATUS_OFFSET)
/* SYSPLL registers */
#define SYSPLL_CTRL (IMX9_SYSPLL_BASE + PLL_CTRL_OFFSET)
#define SYSPLL_SPREAD_SPECTRUM (IMX9_SYSPLL_BASE + PLL_SPREAD_SPECTRUM_OFFSET)
#define SYSPLL_NUMERATOR (IMX9_SYSPLL_BASE + PLL_NUMERATOR_OFFSET)
#define SYSPLL_DENOMINATOR (IMX9_SYSPLL_BASE + PLL_DENOMINATOR_OFFSET)
#define SYSPLL_DIV (IMX9_SYSPLL_BASE + PLL_DIV_OFFSET)
#define SYSPLL_DFS_CTRL_0 (IMX9_SYSPLL_BASE + PLL_DFS_CTRL_0_OFFSET)
#define SYSPLL_DFS_DIV_0 (IMX9_SYSPLL_BASE + PLL_DFS_DIV_0_OFFSET)
#define SYSPLL_DFS_CTRL_1 (IMX9_SYSPLL_BASE + PLL_DFS_CTRL_1_OFFSET)
#define SYSPLL_DFS_DIV_1 (IMX9_SYSPLL_BASE + PLL_DFS_DIV_1_OFFSET)
#define SYSPLL_DFS_CTRL_2 (IMX9_SYSPLL_BASE + PLL_DFS_CTRL_2_OFFSET)
#define SYSPLL_DFS_DIV_2 (IMX9_SYSPLL_BASE + PLL_DFS_DIV_2_OFFSET)
#define SYSPLL_PLL_STATUS (IMX9_SYSPLL_BASE + PLL_PLL_STATUS_OFFSET)
#define SYSPLL_DFS_STATUS (IMX9_SYSPLL_BASE + PLL_DFS_STATUS_OFFSET)
/* ARMPLL registers */
#define ARMPLL_CTRL (IMX9_ARMPLL_BASE + PLL_CTRL_OFFSET)
#define ARMPLL_DIV (IMX9_ARMPLL_BASE + PLL_DIV_OFFSET)
#define ARMPLL_PLL_STATUS (IMX9_ARMPLL_BASE + PLL_PLL_STATUS_OFFSET)
/* AUDIOPLL registers */
#define AUDIOPLL_CTRL (IMX9_AUDIOPLL_BASE + PLL_CTRL_OFFSET)
#define AUDIOPLL_SPREAD_SPECTRUM (IMX9_AUDIOPLL_BASE + PLL_SPREAD_SPECTRUM_OFFSET)
#define AUDIOPLL_NUMERATOR (IMX9_AUDIOPLL_BASE + PLL_NUMERATOR_OFFSET)
#define AUDIOPLL_DENOMINATOR (IMX9_AUDIOPLL_BASE + PLL_DENOMINATOR_OFFSET)
#define AUDIOPLL_DIV (IMX9_AUDIOPLL_BASE + PLL_DIV_OFFSET)
#define AUDIOPLL_PLL_STATUS (IMX9_AUDIOPLL_BASE + PLL_PLL_STATUS_OFFSET)
/* DRAMPLL registers */
#define DRAMPLL_CTRL (IMX9_DRAMPLL_BASE + PLL_CTRL_OFFSET)
#define DRAMPLL_SPREAD_SPECTRUM (IMX9_DRAMPLL_BASE + PLL_SPREAD_SPECTRUM_OFFSET)
#define DRAMPLL_NUMERATOR (IMX9_DRAMPLL_BASE + PLL_NUMERATOR_OFFSET)
#define DRAMPLL_DENOMINATOR (IMX9_DRAMPLL_BASE + PLL_DENOMINATOR_OFFSET)
#define DRAMPLL_DIV (IMX9_DRAMPLL_BASE + PLL_DIV_OFFSET)
#define DRAMPLL_PLL_STATUS (IMX9_DRAMPLL_BASE + PLL_PLL_STATUS_OFFSET)
/* VIDEOPLL registers */
#define VIDEOPLL_CTRL (IMX9_VIDEOPLL_BASE + PLL_CTRL_OFFSET)
#define VIDEOPLL_SPREAD_SPECTRUM (IMX9_VIDEOPLL_BASE + PLL_SPREAD_SPECTRUM_OFFSET)
#define VIDEOPLL_NUMERATOR (IMX9_VIDEOPLL_BASE + PLL_NUMERATOR_OFFSET)
#define VIDEOPLL_DENOMINATOR (IMX9_VIDEOPLL_BASE + PLL_DENOMINATOR_OFFSET)
#define VIDEOPLL_DIV (IMX9_VIDEOPLL_BASE + PLL_DIV_OFFSET)
#define VIDEOPLL_PLL_STATUS (IMX9_VIDEOPLL_BASE + PLL_PLL_STATUS_OFFSET)
/* PLL Control (CTRL) */
#define PLL_CTRL_POWERUP (1 << 0) /* Bit 0: Power up PLL */
#define PLL_CTRL_CLKMUX_EN (1 << 1) /* Bit 1: Enable CLKMUX output */
#define PLL_CTRL_CLKMUX_BYPASS (1 << 2) /* Bit 2: Enable CLKMUX bypass */
#define PLL_CTRL_SPREADCTL (1 << 8) /* Bit 8: Modulation Type Select */
#define PLL_CTRL_HW_CTRL_SEL (1 << 16) /* Bit 16: Hardware Control Select */
#define PLL_CTRL_LOCK_BYPASS (1 << 31) /* Bit 31: Lock bypass */
/* Spread Spectrum (SPREAD_SPECTRUM) */
#define PLL_SPREAD_SPECTRUM_STEP_SHIFT (0) /* Bits 14-0: Set spread spectrum step */
#define PLL_SPREAD_SPECTRUM_STEP_MASK (0x7fff << PLL_SPREAD_SPECTRUM_STEP_SHIFT)
#define PLL_SPREAD_SPECTRUM_STEP(n) (((n) << PLL_SPREAD_SPECTRUM_STEP_SHIFT) & PLL_SPREAD_SPECTRUM_STEP_MASK)
#define PLL_SPREAD_SPECTRUM_ENABLE (1 << 15) /* Bit 15: Enable spread spectrum */
#define PLL_SPREAD_SPECTRUM_STOP_SHIFT (16) /* Bits 16-31: Set spread spectrum stop */
#define PLL_SPREAD_SPECTRUM_STOP_MASK (0xffff << PLL_SPREAD_SPECTRUM_STOP_SHIFT)
#define PLL_SPREAD_SPECTRUM_STOP(n) (((n) << PLL_SPREAD_SPECTRUM_STOP_SHIFT) & PLL_SPREAD_SPECTRUM_STOP_MASK)
/* Numerator (NUMERATOR) */
#define PLL_NUMERATOR_MFN_SHIFT (2) /* Bits 2-31: Numerator MFN value */
#define PLL_NUMERATOR_MFN_MASK (0x3fffffff << PLL_NUMERATOR_MFN_SHIFT)
#define PLL_NUMERATOR_MFN(n) (((n) << PLL_NUMERATOR_MFN_SHIFT) & PLL_NUMERATOR_MFN_MASK)
/* Denominator (DENOMINATOR) */
#define PLL_DENOMINATOR_MFD_SHIFT (0) /* Bits 0-29: Denominator MFD value */
#define PLL_DENOMINATOR_MFD_MASK (0x3fffffff << PLL_DENOMINATOR_MFD_SHIFT)
#define PLL_DENOMINATOR_MFD(n) (((n) << PLL_DENOMINATOR_MFD_SHIFT) & PLL_DENOMINATOR_MFD_MASK)
/* PLL Dividers (DIV) */
#define PLL_DIV_ODIV_SHIFT (0) /* Bits 0-7: Output Frequency Divider for Clock Output */
#define PLL_DIV_ODIV_MASK (0xff << PLL_DIV_ODIV_SHIFT)
#define PLL_DIV_ODIV(n) (((n) << PLL_DIV_ODIV_SHIFT) & PLL_DIV_ODIV_MASK)
#define PLL_DIV_RDIV_SHIFT (13) /* Bits 13-15: Input Clock Predivider */
#define PLL_DIV_RDIV_MASK (0x7 << PLL_DIV_RDIV_SHIFT)
#define PLL_DIV_RDIV(n) (((n) << PLL_DIV_RDIV_SHIFT) & PLL_DIV_RDIV_MASK)
#define PLL_DIV_MFI_SHIFT (16) /* Bits 16-24: Integer Portion of Loop Divider */
#define PLL_DIV_MFI_MASK (0x1ff << PLL_DIV_MFI_SHIFT)
#define PLL_DIV_MFI(n) (((n) << PLL_DIV_MFI_SHIFT) & PLL_DIV_MFI_MASK)
/* DFS Control (DFS_CTRL_0 - DFS_CTRL_2) */
#define PLL_DFS_HW_CTRL_SEL (1 << 16) /* Bit 16: Hardware Control Select */
#define PLL_DFS_BYPASS_EN (1 << 23) /* Bit 23: Bypass Enable */
#define PLL_DFS_CLKOUT_DIVBY2_EN (1 << 29) /* Bit 29: DFS Clock Output Divide by 2 Enable */
#define PLL_DFS_CLKOUT_EN (1 << 30) /* Bit 30: DFS Clock Output Enable */
#define PLL_DFS_ENABLE (1 << 31) /* Bit 31: DFS Block Enable */
/* DFS Division_a (DFS_DIV_0 - DFS_DIV_2) */
#define PLL_DFS_MFN_SHIFT (0) /* Bits 0-2: MFN */
#define PLL_DFS_MFN_MASK (0x7 << PLL_DFS_MFN_SHIFT)
#define PLL_DFS_MFN(n) (((n) << PLL_DFS_MFN_SHIFT) & PLL_DFS_MFN_MASK)
#define PLL_DFS_MFI_SHIFT (8) /* Bits 8-15: MFI */
#define PLL_DFS_MFI_MASK (0xff << PLL_DFS_MFI_SHIFT)
#define PLL_DFS_MFI(n) (((n) << PLL_DFS_MFI_SHIFT) & PLL_DFS_MFI_MASK)
/* PLL Dividers (DIV) */
#define PLL_PLL_STATUS_PLL_LOCK (1 << 0) /* Bit 0: PLL is locked */
#define PLL_PLL_STATUS_PLL_LOL (1 << 1) /* Bit 1: PLL lock is lost */
#define PLL_PLL_STATUS_ANA_MFN_SHIFT (2)
#define PLL_PLL_STATUS_ANA_MFN_MASK (0x3fffffff << PLL_PLL_STATUS_ANA_MFN_SHIFT)
#define PLL_PLL_STATUS_ANA_MFN(n) (((n) << PLL_PLL_STATUS_ANA_MFN_SHIFT) & PLL_PLL_STATUS_ANA_MFN_MASK)
/* DFS Status (DFS_STATUS) */
#define PLL_DFS_STATUS_DFS_OK_SHIFT (0) /* Bits 0-2: DFS OK status */
#define PLL_DFS_STATUS_DFS_OK_MASK (0x7 << PLL_DFS_STATUS_DFS_OK_SHIFT)
#define PLL_DFS_STATUS_DFS_OK(n) (((n) << PLL_DFS_STATUS_DFS_OK_SHIFT) & PLL_DFS_STATUS_DFS_OK_MASK)
#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX95_IMX95_PLL_H */
+2
View File
@@ -34,6 +34,8 @@
# include "hardware/imx93/imx93_ccm.h"
# include "hardware/imx93/imx93_pll.h"
#elif defined(CONFIG_ARCH_CHIP_IMX95)
# include "hardware/imx95/imx95_ccm.h"
# include "hardware/imx95/imx95_pll.h"
#else
# error Unrecognized i.MX9 architecture
#endif
@@ -32,6 +32,7 @@
#if defined(CONFIG_ARCH_CHIP_IMX93)
# include "hardware/imx93/imx93_pinmux.h"
#elif defined(CONFIG_ARCH_CHIP_IMX95)
# include "hardware/imx95/imx95_pinmux.h"
#else
# error Unrecognized i.MX9 architecture
#endif
+65 -5
View File
@@ -327,9 +327,11 @@ static void imx9_reset(struct sdio_dev_s *dev);
static sdio_capset_t imx9_capabilities(struct sdio_dev_s *dev);
static sdio_statset_t imx9_status(struct sdio_dev_s *dev);
static void imx9_widebus(struct sdio_dev_s *dev, bool enable);
#ifndef CONFIG_IMX9_CLK_OVER_SCMI
static bool imx9_sdcard_hs_mode(struct sdio_dev_s *dev, bool set);
static uint32_t imx9_frequency(struct sdio_dev_s *dev,
unsigned long frequency);
#endif
static void imx9_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate);
static int imx9_attach(struct sdio_dev_s *dev);
@@ -1648,7 +1650,20 @@ static void imx9_widebus(struct sdio_dev_s *dev, bool wide)
regval &= ~USDHC_PROCTL_DTW_MASK;
if (wide)
{
regval |= USDHC_PROCTL_DTW_4BIT;
/* Only USDHC1 supports 8-bit data width. USDHC2 is limited to
* 4-bit according to chip spec.
*/
#ifdef CONFIG_IMX9_USDHC1_WIDTH_D1_D8
if (priv->addr == IMX9_USDHC1_BASE)
{
regval |= USDHC_PROCTL_DTW_8BIT;
}
else
#endif
{
regval |= USDHC_PROCTL_DTW_4BIT;
}
}
else
{
@@ -1658,6 +1673,8 @@ static void imx9_widebus(struct sdio_dev_s *dev, bool wide)
putreg32(regval, priv->addr + IMX9_USDHC_PROCTL_OFFSET);
}
#ifndef CONFIG_IMX9_CLK_OVER_SCMI
/****************************************************************************
* Name: imx9_sdcard_hs_mode
*
@@ -1875,9 +1892,12 @@ static uint32_t imx9_frequency(struct sdio_dev_s *dev,
/* Return the new divisor information */
return USDHC_SYSCTL_SDCLKFS_DIV(prescaler) | USDHC_SYSCTL_DVS_DIV(divisor);
return USDHC_SYSCTL_SDCLKFS_DIV(prescaler) |
USDHC_SYSCTL_DVS_DIV(divisor);
}
#endif /* !CONFIG_IMX9_CLK_OVER_SCMI */
/****************************************************************************
* Name: imx9_clock
*
@@ -1897,13 +1917,15 @@ static void imx9_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate)
{
struct imx9_dev_s *priv = (struct imx9_dev_s *)dev;
uint32_t regval;
#ifndef CONFIG_IMX9_CLK_OVER_SCMI
unsigned speed;
#endif
/* Clear the old prescaler and divisor values so that new ones can be
* ORed in.
*/
regval = getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET);
regval = getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET);
regval &= ~(USDHC_SYSCTL_SDCLKFS_MASK | USDHC_SYSCTL_DVS_MASK);
/* Select the new prescaler and divisor values based on the requested
@@ -1918,8 +1940,14 @@ static void imx9_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate)
{
/* Clock is disabled */
mcinfo("DISABLED, SYSCTRL: %08" PRIx32 "\n", regval);
putreg32(regval, priv->addr + IMX9_USDHC_SYSCTL_OFFSET);
mcinfo("DISABLED, SYSCTRL: %08" PRIx32 "\n",
getreg32(priv->addr + IMX9_USDHC_SYSCTL_OFFSET));
#ifdef CONFIG_IMX9_CLK_OVER_SCMI
return;
#else
speed = 0;
#endif
}
break;
@@ -1928,13 +1956,19 @@ static void imx9_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate)
/* Initial ID mode clocking (<400KHz) */
mcinfo("IDMODE\n");
speed = BOARD_USDHC_IDMODE_SPEED;
/* Put out an additional 80 clocks in case this is a power-up
* sequence.
*/
#ifdef CONFIG_IMX9_CLK_OVER_SCMI
regval |= (BOARD_USDHC_IDMODE_PRESCALER |
BOARD_USDHC_IDMODE_DIVISOR |
USDHC_SYSCTL_INITA);
#else
speed = BOARD_USDHC_IDMODE_SPEED;
regval |= USDHC_SYSCTL_INITA;
#endif
}
break;
@@ -1943,7 +1977,12 @@ static void imx9_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate)
/* MMC normal operation clocking */
mcinfo("MMCTRANSFER\n");
#ifdef CONFIG_IMX9_CLK_OVER_SCMI
regval |= (BOARD_USDHC_MMCMODE_PRESCALER |
BOARD_USDHC_MMCMODE_DIVISOR);
#else
speed = BOARD_USDHC_MMCMODE_SPEED;
#endif
}
break;
@@ -1952,7 +1991,12 @@ static void imx9_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate)
/* SD normal operation clocking (narrow 1-bit mode) */
mcinfo("1BITTRANSFER\n");
#ifdef CONFIG_IMX9_CLK_OVER_SCMI
regval |= (BOARD_USDHC_SD1MODE_PRESCALER |
BOARD_USDHC_SD1MODE_DIVISOR);
#else
speed = BOARD_USDHC_SD1MODE_SPEED;
#endif
}
break;
@@ -1960,6 +2004,11 @@ static void imx9_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate)
{
/* SD normal operation clocking (wide 4-bit mode) */
#ifdef CONFIG_IMX9_CLK_OVER_SCMI
mcinfo("4BITTRANSFER\n");
regval |= (BOARD_USDHC_SD4MODE_PRESCALER |
BOARD_USDHC_SD4MODE_DIVISOR);
#else
mcinfo("SDTRANSFER\n");
speed = BOARD_USDHC_SDMODE_SPEED;
@@ -1979,14 +2028,17 @@ static void imx9_clock(struct sdio_dev_s *dev, enum sdio_clock_e rate)
}
}
}
#endif
}
break;
}
#ifndef CONFIG_IMX9_CLK_OVER_SCMI
if (speed > 0)
{
regval |= imx9_frequency(dev, speed);
}
#endif
putreg32(regval, priv->addr + IMX9_USDHC_SYSCTL_OFFSET);
@@ -3453,9 +3505,13 @@ struct sdio_dev_s *imx9_usdhc_initialize(int slotno)
/* Enable clocks */
#ifdef CONFIG_IMX9_CLK_OVER_SCMI
imx9_configure_clock(USDHC1_DFS1 | CLOCK_DIV(4), true);
#else
imx9_ccm_configure_root_clock(CCM_CR_USDHC1, SYS_PLL1PFD1, 2);
imx9_get_rootclock(CCM_CR_USDHC1, &priv->root_clock_freq);
imx9_ccm_gate_on(CCM_LPCG_USDHC1, true);
#endif
break;
#endif
@@ -3488,9 +3544,13 @@ struct sdio_dev_s *imx9_usdhc_initialize(int slotno)
/* Enable clocks */
#ifdef CONFIG_IMX9_CLK_OVER_SCMI
imx9_configure_clock(USDHC2_DFS1 | CLOCK_DIV(4), true);
#else
imx9_ccm_configure_root_clock(CCM_CR_USDHC2, SYS_PLL1PFD1, 2);
imx9_get_rootclock(CCM_CR_USDHC2, &priv->root_clock_freq);
imx9_ccm_gate_on(CCM_LPCG_USDHC2, true);
#endif
mcinfo("Enabled clocks\n");
@@ -96,6 +96,19 @@
/* Note: Need to set the SION for cmd and data pads (ERR052021) */
/* USDHC1 - eMMC 8-bit */
#define PIN_USDHC1_D0_MUX IOMUX_CFG(IOMUXC_PAD_SD1_DATA0_USDHC1_DATA0, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
#define PIN_USDHC1_D1_MUX IOMUX_CFG(IOMUXC_PAD_SD1_DATA1_USDHC1_DATA1, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
#define PIN_USDHC1_D2_MUX IOMUX_CFG(IOMUXC_PAD_SD1_DATA2_USDHC1_DATA2, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
#define PIN_USDHC1_D3_MUX IOMUX_CFG(IOMUXC_PAD_SD1_DATA3_USDHC1_DATA3, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
#define PIN_USDHC1_D4_MUX IOMUX_CFG(IOMUXC_PAD_SD1_DATA4_USDHC1_DATA4, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
#define PIN_USDHC1_D5_MUX IOMUX_CFG(IOMUXC_PAD_SD1_DATA5_USDHC1_DATA5, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
#define PIN_USDHC1_D6_MUX IOMUX_CFG(IOMUXC_PAD_SD1_DATA6_USDHC1_DATA6, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
#define PIN_USDHC1_D7_MUX IOMUX_CFG(IOMUXC_PAD_SD1_DATA7_USDHC1_DATA7, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
#define PIN_USDHC1_DCLK_MUX IOMUX_CFG(IOMUXC_PAD_SD1_CLK_USDHC1_CLK, IOMUXC_PAD_DSE_X6 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PD_ON | IOMUXC_PAD_HYS_ST_ON, 0)
#define PIN_USDHC1_CMD_MUX IOMUX_CFG(IOMUXC_PAD_SD1_CMD_USDHC1_CMD, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
#define PIN_USDHC2_D0_MUX IOMUX_CFG(IOMUXC_PAD_SD2_DATA0_USDHC2_DATA0, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
#define PIN_USDHC2_D1_MUX IOMUX_CFG(IOMUXC_PAD_SD2_DATA1_USDHC2_DATA1, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
#define PIN_USDHC2_D2_MUX IOMUX_CFG(IOMUXC_PAD_SD2_DATA2_USDHC2_DATA2, IOMUXC_PAD_DSE_X1 | IOMUXC_PAD_FSEL_FAST | IOMUXC_PAD_PU_ON | IOMUXC_PAD_HYS_ST_ON, IOMUXC_MUX_SION_ON)
@@ -105,21 +118,29 @@
#define PIN_USDHC2_CD_MUX IOMUX_CFG(IOMUXC_PAD_SD2_DATA3_USDHC2_DATA3, IOMUXC_PAD_DSE_X4 | IOMUXC_PAD_FSEL_FAST, 0)
#define PIN_USDHC2_VSELECT_MUX IOMUX_CFG(IOMUXC_PAD_SD2_VSELECT_USDHC2_VSELECT, IOMUXC_PAD_DSE_X5 | IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_PD_ON, 0)
/* 400 KHz for initial inquiry stuff */
/* 390 KHz for initial inquiry stuff */
#define BOARD_USDHC_IDMODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV256
#define BOARD_USDHC_IDMODE_DIVISOR USDHC_SYSCTL_DVS_DIV(2)
#define BOARD_USDHC_IDMODE_SPEED 400000
/* 25MHz for MMC mode */
#define BOARD_USDHC_MMCMODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8
#define BOARD_USDHC_MMCMODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1)
#define BOARD_USDHC_MMCMODE_SPEED 25000000
/* 25MHz for 1-bit wide bus */
#define BOARD_USDHC_SD1MODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV8
#define BOARD_USDHC_SD1MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1)
#define BOARD_USDHC_SD1MODE_SPEED 25000000
/* 50MHz for SD card mode */
/* 50MHz for 4-bit wide bus */
#define BOARD_USDHC_SDMODE_SPEED 50000000
#define BOARD_USDHC_SD4MODE_PRESCALER USDHC_SYSCTL_SDCLKFS_DIV4
#define BOARD_USDHC_SD4MODE_DIVISOR USDHC_SYSCTL_DVS_DIV(1)
#define BOARD_USDHC_SDMODE_SPEED 50000000
/* Set the PLL clocks as follows:
*
@@ -29,4 +29,8 @@ if(CONFIG_BOARDCTL)
endif()
endif()
if(CONFIG_IMX9_USDHC)
list(APPEND SRCS imx9_usdhc.c)
endif()
target_sources(board PRIVATE ${SRCS})
@@ -31,4 +31,8 @@ CSRCS += imx9_reset.c
endif
endif
ifeq ($(CONFIG_IMX9_USDHC),y)
CSRCS += imx9_usdhc.c
endif
include $(TOPDIR)/boards/Board.mk
@@ -61,6 +61,25 @@ int imx9_bringup(void)
}
#endif
#ifdef CONFIG_IMX9_DMA_ALLOC
/* Initialize the DMA memory allocator */
ret = imx9_dma_alloc_init();
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: Failed initialize DMA allocator: %d\n", ret);
}
#endif
#ifdef CONFIG_MMCSD
ret = imx9_usdhc_init();
if (ret < 0)
{
syslog(LOG_ERR, "Failed to init MMCSD driver: %d\n", ret);
}
#endif
UNUSED(ret);
return OK;
}
@@ -0,0 +1,85 @@
/****************************************************************************
* boards/arm64/imx9/imx95-a55-evk/src/imx9_usdhc.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <debug.h>
#include <errno.h>
#include <nuttx/mmcsd.h>
#include "imx9_usdhc.h"
#include "imx95-evk.h"
/****************************************************************************
* Private Data
****************************************************************************/
static struct sdio_dev_s *g_sdio_dev;
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: imx9_usdhc_init
*
* Description:
* Configure the uSDHC driver.
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned
* to indicate the nature of any failure.
*
****************************************************************************/
int imx9_usdhc_init(void)
{
int ret;
/* First, get an instance of the SDIO interface */
finfo("Initializing SDIO slot %d\n", SDIO_SLOTNO);
g_sdio_dev = imx9_usdhc_initialize(SDIO_SLOTNO);
if (!g_sdio_dev)
{
ferr("ERROR: Failed to initialize SDIO slot %d\n", SDIO_SLOTNO);
return -ENODEV;
}
/* Now bind the SDIO interface to the MMC/SD driver */
finfo("Bind SDIO to the MMC/SD driver, minor=%d\n", SDIO_MINOR);
ret = mmcsd_slotinitialize(SDIO_MINOR, g_sdio_dev);
if (ret != OK)
{
ferr("ERROR: Failed to bind SDIO to the MMC/SD driver: %d\n", ret);
return ret;
}
return OK;
}