向 LinuxSH 添加新板卡

Paul Mundt <lethal@linux-sh.org>

本文档试图概述在新的 2.5 和 2.6 内核下,向 LinuxSH 端口添加新板卡的支持所必需的步骤。本文档还试图概述 2.4 和 2.5/2.6 SH 后端之间的一些显著变化。

1. 新的目录结构

首先要注意的是新的目录结构。在 2.4 版本下,大多数板卡特定的代码(除了 stboards)都直接放在 arch/sh/kernel/ 中,而板卡特定的头文件则放在 include/asm-sh/ 中。对于新的内核,代码按照板卡类型、配套芯片类型和 CPU 类型进行分类。此目录层次结构的树状视图如下所示:

板卡特定代码

.
|-- arch
|   `-- sh
|       `-- boards
|           |-- adx
|           |   `-- board-specific files
|           |-- bigsur
|           |   `-- board-specific files
|           |
|           ... more boards here ...
|
`-- include
    `-- asm-sh
        |-- adx
        |   `-- board-specific headers
        |-- bigsur
        |   `-- board-specific headers
        |
        .. more boards here ...

接下来,对于配套芯片

.
`-- arch
    `-- sh
        `-- cchips
            `-- hd6446x
                `-- hd64461
                    `-- cchip-specific files

等等。配套芯片的头文件与板卡特定的头文件处理方式相同。因此,include/asm-sh/hd64461 是所有 hd64461 特定头文件的所在地。

最后,CPU 系列支持也被抽象出来

.
|-- arch
|   `-- sh
|       |-- kernel
|       |   `-- cpu
|       |       |-- sh2
|       |       |   `-- SH-2 generic files
|       |       |-- sh3
|       |       |   `-- SH-3 generic files
|       |       `-- sh4
|       |           `-- SH-4 generic files
|       `-- mm
|           `-- This is also broken out per CPU family, so each family can
|               have their own set of cache/tlb functions.
|
`-- include
    `-- asm-sh
        |-- cpu-sh2
        |   `-- SH-2 specific headers
        |-- cpu-sh3
        |   `-- SH-3 specific headers
        `-- cpu-sh4
            `-- SH-4 specific headers

应该注意的是,CPU 子类型_没有_被抽象出来。因此,这些仍然需要由 CPU 系列特定的代码处理。

2. 添加新板卡

首先要确定的是,您要添加的板卡是独立的,还是属于一个板卡系列,该系列中的大部分板卡可以共享相同的板卡特定代码,只有细微差别。

在第一种情况下,这只是在 arch/sh/boards/ 中为您的板卡创建一个目录,并添加规则以将您的板卡与构建系统连接起来(更多内容将在下一节中介绍)。但是,对于板卡系列,最好有一个通用的顶级 arch/sh/boards/ 目录,然后用每个系列成员的子目录填充它。Solution Engine 和 hp6xx 板卡都是这方面的例子。

在您设置好新的 arch/sh/boards/ 目录后,请记住,您还应该在 include/asm-sh 中为该板卡的本地头文件添加一个目录(如果将有多个)。为了与构建系统无缝互操作,最好让此目录与 arch/sh/boards/ 目录的名称相同,但是如果您的板卡再次属于一个系列,构建系统可以通过某种方式来处理这种情况(通过 incdir-y 重载),您可以随意以系列成员的名称来命名该目录。

每个板卡都需要在 arch/sh/boards 和 include/asm-sh/ 层次结构中拥有一些东西。为了更好地解释这一点,我们使用一些示例来添加一个虚构的板卡。对于设置代码,我们至少需要为 get_system_type() 和 platform_setup() 提供定义。对于我们的虚构板卡,这可能类似于

/*
* arch/sh/boards/vapor/setup.c - Setup code for imaginary board
*/
#include <linux/init.h>

const char *get_system_type(void)
{
        return "FooTech Vaporboard";
}

int __init platform_setup(void)
{
        /*
        * If our hardware actually existed, we would do real
        * setup here. Though it's also sane to leave this empty
        * if there's no real init work that has to be done for
        * this board.
        */

        /* Start-up imaginary PCI ... */

        /* And whatever else ... */

        return 0;
}

我们的新虚构板卡也必须与 machvec 关联,以便它可以发挥任何作用。

machvec 函数分为几个类别

  • 用于 IO 内存(inb 等)和 PCI/主内存(readb 等)的 I/O 函数。

  • I/O 映射函数(ioport_map、ioport_unmap 等)。

  • 一个“心跳”函数。

  • PCI 和 IRQ 初始化例程。

  • 一致性分配器(适用于需要特殊分配器的板卡,特别是从一些板卡特定的 SRAM 中分配 DMA 句柄)。

随着时间的推移,machvec 函数会不断添加和删除,因此请始终查阅 include/asm-sh/machvec.h,了解 machvec 的当前状态。

内核会在启动时自动为 machvec 中未定义的函数指针封装通用例程,因为 machvec 函数在整个树中被无条件引用。有些板卡具有极其稀疏的 machvec(例如 dreamcast 和 sh03),而另一些板卡则必须定义几乎所有内容(rts7751r2d)。

添加新机器相对简单(以 vapor 为例)

如果板卡特定的定义非常精简,就像绝大多数板卡的情况一样,那么只需一个板卡特定的头文件就足够了。

  • 添加一个新文件 include/asm-sh/vapor.h,其中包含任何机器特定 IO 函数的原型,这些原型以机器名称为前缀,例如 vapor_inb。在填充机器向量时,将需要这些原型。

    请注意,这些原型是通过将 __IO_PREFIX 设置为合理值来自动生成的。一个典型的例子是

    #define __IO_PREFIX vapor
    #include <asm/io_generic.h>
    

    在板卡特定的头文件中。任何仍在拥有旧 io.h 的移植板卡都应完全删除它并切换到新模型。

  • 将机器向量定义添加到板卡的 setup.c 中。至少,必须将其定义为如下所示:

    struct sh_machine_vector mv_vapor __initmv = {
            .mv_name = "vapor",
    };
    ALIAS_MV(vapor)
    
  • 最后,添加一个文件 arch/sh/boards/vapor/io.c,其中包含机器特定 io 函数的定义(如果有足够的函数需要)。

3. 与构建系统连接

现在我们已经设置了相应的目录,并且所有板卡特定的代码都已就位,是时候看看如何让整个混乱的情况融入构建系统了。

现在,构建系统的很大一部分是完全动态的,只需要在其中各处进行适当的输入即可完成工作。

首先要做的是在 arch/sh/Kconfig 中,在“系统类型”菜单下添加一个条目

config SH_VAPOR
        bool "Vapor"
        help
        select Vapor if configuring for a FooTech Vaporboard.

接下来,必须将其添加到 arch/sh/Makefile 中。所有板卡都需要一个 machdir-y 条目才能进行构建。此条目必须是在 arch/sh/boards 中显示的板卡目录的名称,即使它位于子目录中(在这种情况下,需要列出 arch/sh/boards/ 下面的所有父目录)。对于我们的新板卡,此条目可以如下所示:

machdir-$(CONFIG_SH_VAPOR)  += vapor

前提是我们将所有内容都放在 arch/sh/boards/vapor/ 目录中。

接下来,构建系统会假设您的 include/asm-sh 目录的名称也相同。如果情况并非如此(就像属于一个通用系列的多个板卡的情况一样),那么目录名称需要隐式地附加到 incdir-y。现有代码管理 Solution Engine 和 hp6xx 板卡的情况,因此请查看这些代码以获取示例。

一旦解决了这个问题,是时候添加一个 mach 类型的条目了。这是通过在 arch/sh/tools/mach-types 列表的末尾添加一个条目来完成的。执行此操作的方法是不言自明的,因此我们不会在此处浪费空间重复说明。完成此操作后,如果需要,您可以在整个通用代码中的某个位置使用对您的板卡的隐式检查,例如:

/* Make sure we're on the FooTech Vaporboard */
if (!mach_is_vapor())
        return -ENODEV;

还要注意,无论 mach-types 条目是否全部大写,mach_is_boardname() 检查都会被隐式强制转换为小写。如果您真的在意,可以阅读该脚本,但是它非常丑陋,因此您可能不想这样做。

现在剩下的就是为您的新板卡提供一个 defconfig。这样,最终使用此板卡的其他人员可以简单地使用此配置作为参考,而不是尝试猜测应该在其中使用哪些设置。

此外,一旦您为您的新板卡复制了示例 .config(假设 arch/sh/configs/vapor_defconfig),您也可以将其直接用作构建目标,并且它将在帮助文本中被隐式列出。

查看“make help”输出,您现在应该看到类似以下内容:

特定于架构的目标 (sh)

zImage

压缩内核映像 (arch/sh/boot/zImage)

adx_defconfig

为 adx 构建

cqreek_defconfig

为 cqreek 构建

dreamcast_defconfig

为 dreamcast 构建

...

vapor_defconfig

为 vapor 构建

然后,这允许您执行以下操作:

$ make ARCH=sh CROSS_COMPILE=sh4-linux- vapor_defconfig vmlinux

这将反过来复制此板卡的 defconfig,通过 oldconfig 运行它(提示您自从创建以来是否有任何新选项),然后开始为您新板卡创建一个功能正常的内核。