SD Express驱动架构解析:Linux MMC Core框架与O2Micro GG8芯片适配

概述

本文深入分析Linux内核MMC子系统对SD Express的支持框架,以及Bayhub(O2Micro) GG8芯片驱动如何适配到内核框架。

SD Express技术背景

SD Express是SD协会发布的第七代SD标准,核心特性:

特性 SD 6.x SD Express
最大容量 2TB (SDXC) 128TB (SDXC)
最大速度 ~100 MB/s (UHS-II) ~4 GB/s (PCIe 4.0 x2)
总线协议 SD/UHS-II PCIe/NVMe

Linux MMC子系统架构

整体架构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
┌─────────────────────────────────────────────────────────────────┐
│ Linux MMC 子系统架构 │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│ User Space (Block Layer) │
└─────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│ MMC Block Driver (mmc_blk) │
│ • 将MMC设备呈现为块设备 │
│ • 处理读写请求、队列管理 │
└─────────────────────────────────────────────────────────────────┘


┌─────────────────────────────────────────────────────────────────┐
│ MMC Core (mmc_core) │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────────┐ │
│ │ mmc_bus_ops │ │ mmc_card │ │ MMC Protocol │ │
│ │ • suspend │ │ • CID/CSD │ │ • SD Express │ │
│ │ • resume │ │ • SCR/SSR │ │ • NVMe切换 │ │
│ │ • remove │ │ • 能力检测 │ │ • 初始化流程 │ │
│ └───────────────┘ └───────────────┘ └───────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ sdhci-pci-o2micro│ │ sdhci-pci-gli │ │ 其他Host驱动 │
│ (Bayhub GG8) │ │ (GL874/GL9750) │ │ │
└──────────────────┘ └──────────────────┘ └──────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ SD Host Controller │
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────────┐ │
│ │ SDHCI Core │ │ PCI/AMBA │ │ Platform Data │ │
│ │ • DMA │ │ Bus Layer │ │ • GPIO/Clock │ │
│ │ • Interrupts │ │ │ │ │ │
│ └───────────────┘ └───────────────┘ └───────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

SD Express支持框架

1. Capability声明

在内核MMC框架中,Host驱动需要声明支持SD Express:

1
2
3
// mmc.h - MMC capability定义
#define MMC_CAP2_SD_EXP (1 << 0) // SD Express支持
#define MMC_CAP2_SD_EXP_1_2V (1 << 1) // SD Express 1.2V支持

2. SD Express初始化回调

1
2
3
4
5
6
7
// mmc.h - Host操作接口
struct mmc_host_ops {
// ... 其他回调 ...

// SD Express初始化回调
int (*init_sd_express)(struct mmc_host *mmc, struct mmc_ios *ios);
};

当MMC Core检测到需要切换到SD Express模式时,调用此回调。

3. SD Express状态机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
┌─────────────────────────────────────────────────────────────────┐
│ SD Express 状态机 │
└─────────────────────────────────────────────────────────────────┘

[1] 初始化SD卡


[2] 检测SD Express能力 (SCR[60] = 1)


[3] 协商电压 (1.8V)


[4] 执行PCIe链路训练


[5] 等待Card发出PCIe电源通知


[6] 调用init_sd_express回调


[7] 切换Host到PCIe模式


[8] 通知NVMe驱动接管

GG8芯片适配分析

1. Device ID定义

1
2
3
4
5
// sdhci-pci.h - Bayhub GG8设备ID
#define PCI_DEVICE_ID_O2_GG8_9860 0x9860
#define PCI_DEVICE_ID_O2_GG8_9861 0x9861
#define PCI_DEVICE_ID_O2_GG8_9862 0x9862
#define PCI_DEVICE_ID_O2_GG8_9863 0x9863

2. SD Express切换实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// sdhci-pci-o2micro.c - GG8 SD Express初始化
static int sdhci_pci_o2_init_sd_express(struct mmc_host *mmc,
struct mmc_ios *ios)
{
struct sdhci_host *host = mmc_priv(mmc);
struct sdhci_pci_slot *slot = sdhci_priv(host);
struct sdhci_pci_chip *chip = slot->chip;
u8 scratch8;
u16 scratch16;
int ret;

// Step 1: 禁用时钟
sdhci_writeb(host, 0, SDHCI_CLOCK_CONTROL);

// Step 2: 设置VDD2电压
scratch8 = sdhci_readb(host, SDHCI_POWER_CONTROL);
scratch8 &= 0x0F;

if (host->mmc->ios.timing == MMC_TIMING_SD_EXP_1_2V &&
host->mmc->caps2 & MMC_CAP2_SD_EXP_1_2V) {
scratch8 |= SDHCI_VDD2_POWER_ON | SDHCI_VDD2_POWER_120;
} else {
scratch8 |= SDHCI_VDD2_POWER_ON | SDHCI_VDD2_POWER_180;
}
sdhci_writeb(host, scratch8, SDHCI_POWER_CONTROL);

// Step 3: 解锁WP寄存器
pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch8);
scratch8 &= 0x7f;
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch8);

// Step 4: 等待Card发出clkreqn信号
ret = read_poll_timeout(sdhci_readb, scratch8,
!(scratch8 & BIT(0)),
1, 30000, false, host, O2_SD_EXP_INT_REG);

if (!ret) {
// Step 5: 切换到PCIe模式
scratch16 = sdhci_readw(host, O2_SD_PCIE_SWITCH);
scratch16 |= BIT(8); // 触发模式切换
sdhci_writew(host, scratch16, O2_SD_PCIE_SWITCH);
} else {
// 切换失败,恢复到Legacy模式
scratch8 = sdhci_readb(host, SDHCI_POWER_CONTROL);
scratch8 &= 0x0F;
sdhci_writeb(host, scratch8, SDHCI_POWER_CONTROL);

host->mmc->ios.timing = MMC_TIMING_LEGACY;
// ... 恢复到SD模式 ...
}

// Step 6: 锁定WP寄存器
pci_read_config_byte(chip->pdev, O2_SD_LOCK_WP, &scratch8);
scratch8 |= 0x80;
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch8);

return 0;
}

3. Capability配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// sdhci-pci-o2micro.c - probe_slot函数中
case PCI_DEVICE_ID_O2_GG8_9860:
case PCI_DEVICE_ID_O2_GG8_9861:
case PCI_DEVICE_ID_O2_GG8_9862:
case PCI_DEVICE_ID_O2_GG8_9863:
// 禁用SDIO功能(GG8不支持)
host->mmc->caps2 |= MMC_CAP2_NO_SDIO;

// 启用SD Express支持
host->mmc->caps2 |= MMC_CAP2_SD_EXP | MMC_CAP2_SD_EXP_1_2V;

// 启用Hardware Reset
host->mmc->caps |= MMC_CAP_HW_RESET;

// 注册SD Express初始化回调
host->mmc_host_ops.init_sd_express = sdhci_pci_o2_init_sd_express;
break;

4. 关键寄存器定义

1
2
3
4
5
6
// GG8 SD Express关键寄存器
#define O2_SD_PCIE_SWITCH 0x54 // PCIe模式切换寄存器
#define O2_SD_LOCK_WP 0xC8 // 写保护锁定寄存器
#define O2_SD_EXP_INT_REG 0x1E0 // Express中断寄存器
#define O2_SD_PARA_SET_REG1 0x444 // 参数设置寄存器
#define O2_SD_VDDX_CTRL_REG 0x508 // VDD控制寄存器

与MMC Core的协作流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
┌─────────────────────────────────────────────────────────────────┐
│ GG8驱动与MMC Core协作流程 │
└─────────────────────────────────────────────────────────────────┘

┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ MMC Core │ │ sdhci-pci │ │ GG8 │
│ │ │ -o2micro │ │ Hardware │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
│ 1. 枚举SD Express卡│ │
│───────────────────►│ │
│ │ │
│ 2. 检测SCR[60] │ │
│◄───────────────────│ │
│ │ │
│ 3. 调用init_sd_express │
│───────────────────►│ │
│ │ │
│ │ 4. 关闭SD时钟 │
│ │───────────────────►│
│ │ │
│ │ 5. 设置VDD2电压 │
│ │───────────────────►│
│ │ │
│ │ 6. 等待clkreqn │
│ │◄───────────────────│
│ │ │
│ │ 7. 写PCIE_SWITCH │
│ │───────────────────►│
│ │ │
│ │ 8. 卡切换PCIe模式 │
│ │◄───────────────────│
│ │ │
│ 9. NVMe驱动接管 │ │
│◄───────────────────│ │

双模式支持

GG8芯片支持两种工作模式:

模式 协议 用途
SD Legacy SD 4.0/UHS-II 兼容普通SD卡
SD Express PCIe/NVMe 高速存储

MMC Core根据卡的能力自动选择模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// mmc_init_sd_express - MMC Core中的SD Express初始化
static int mmc_init_sd_express(struct mmc_host *host)
{
// 检查卡是否支持SD Express
if (!(card->scr[1] & SD_SCR_SD_EXPRESS))
return -ENODEV;

// 设置1.8V电压
host->ios.timing = MMC_TIMING_SD_EXP;
mmc_set_ios(host);

// 调用Host驱动的init_sd_express回调
if (host->ops->init_sd_express)
ret = host->ops->init_sd_express(host, &host->ios);

return ret;
}

总结

本文分析了Linux MMC子系统中SD Express的支持框架:

  1. MMC Core提供的能力

    • Capability声明机制
    • 状态机管理
    • 回调接口定义
  2. GG8芯片的适配点

    • Device ID注册
    • init_sd_express回调实现
    • PCIe模式切换控制
    • 错误恢复机制
  3. 协作流程

    • MMC Core主导流程
    • Host驱动提供硬件操作
    • NVMe驱动负责接管

这种分层架构设计使得不同厂商的SD Express控制器可以复用通用的MMC Core代码,只需实现厂商特定的硬件操作。