1、linux下通过 cmdline 实现
参考 :Documentation/admin-guide/kernel-parameters.txt
libata.force= [LIBATA] Force configurations. The format is comma
separated list of "[ID:]VAL" where ID is
PORT[.DEVICE]. PORT and DEVICE are decimal numbers
matching port, link or device. Basically, it matches
the ATA ID string printed on console by libata. If
the whole ID part is omitted, the last PORT and DEVICE
values are used. If ID hasn't been specified yet, the
configuration applies to all ports, links and devices.
If only DEVICE is omitted, the parameter applies to
the port and all links and devices behind it. DEVICE
number of 0 either selects the first device or the
first fan-out link behind PMP device. It does not
select the host link. DEVICE number of 15 selects the
host link and device attached to it.
The VAL specifies the configuration to force. As long
as there's no ambiguity shortcut notation is allowed.
For example, both 1.5 and 1.5G would work for 1.5Gbps.
The following configurations can be forced.
* Cable type: 40c, 80c, short40c, unk, ign or sata.
Any ID with matching PORT is used.
* SATA link speed limit: 1.5Gbps or 3.0Gbps.
* Transfer mode: pio[0-7], mwdma[0-4] and udma[0-7].
udma[/][16,25,33,44,66,100,133] notation is also
allowed.
* [no]ncq: Turn on or off NCQ.
* nohrst, nosrst, norst: suppress hard, soft
and both resets.
* dump_id: dump IDENTIFY data.
If there are multiple matching configurations changing
the same attribute, the last one is used.
可以将上面的参数加到 cmdline 中,从uboot传给内核的参数
如果要限制具体那个port , 可以根据 dmesg 来看
So, the tricky part is finding out which port X and device Y (dmesg ataX.YY) is which controller and drive. I think - that notation matches PORT[.DEVICE], but there's also the W:X:Y:Z notation. I'm guessing ataX.YY :)
libata.force=1:1.5G,2:1.5G,3:1.5G
2、uboot下 通过修改 sata controller 实现
我们在 linux 启动的log里经常看到如下信息,
ata2: SATA link up 1.5 Gbps (SStatus 113 SControl 300) .
ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
ata1: SATA link up 6.0 Gbps (SStatus 133 SControl 300)
从SStatus 就可以看出 sata link speed , 0x133 就是6.0Gbps的速度。从 SControl 就可以看到 sata phy 的设置,这个 sata phy register是 sata 控制器的组成部分,如果 sata 接口是 CPU的资源,需要参考cpu 的手册,不过 sata phy register是一个标准,基本所有的控制器设计的时候都按照这个规范来的。以NXP LS1046A ARM64平台为例,就1个sata controller (可以查看serdes配置,0x3040, 0x5a59 还有dts查看sata控制器地址),下面是 SATA status register (PxSSTS) 。
SATA control register (PxSCTL)
# u-boot-ls $ grep PORT_SCR -nR include/
include/ahci.h:54:#define PORT_SCR 0x28 /* SATA phy register block */
include/ahci.h:55:#define PORT_SCR_STAT 0x28 /* SATA phy register: SStatus */
include/ahci.h:56:#define PORT_SCR_CTL 0x2c /* SATA phy register: SControl */
include/ahci.h:57:#define PORT_SCR_ERR 0x30 /* SATA phy register: SError */
include/ahci.h:58:#define PORT_SCR_ACT 0x34 /* SATA phy register: SActive */
include/ahci.h:93:/* PORT_SCR_STAT bits */
include/ahci.h:94:#define PORT_SCR_STAT_DET_MASK 0x3
include/ahci.h:95:#define PORT_SCR_STAT_DET_COMINIT 0x1
include/ahci.h:96:#define PORT_SCR_STAT_DET_PHYRDY 0x3
这里的设置 可以参考 u-boot/board/highbank/ahci.c 来实现
具体实现如下:
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 18b748a..f6078c0 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -251,6 +251,15 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv)
sunxi_dma_init(port_mmio);
#endif
+#ifdef CONFIG_TARGET_YY_XXXXXXXXXXX
+ /* limit sata speed 1.5Gbps */
+ writel(0x311, port_mmio + PORT_SCR_CTL);
+ udelay(1000);
+ writel(0x310, port_mmio + PORT_SCR_CTL);
+ udelay(1000);
+#endif
+
/* Add the spinup command to whatever mode bits may
* already be on in the command register.
*/
@@ -314,7 +323,7 @@ static int ahci_host_init(struct ahci_uc_priv *uc_priv)
/* register linkup ports */
tmp = readl(port_mmio + PORT_SCR_STAT);
- debug("SATA port %d status: 0x%x\n", i, tmp);
+ printf("SATA port %d status: 0x%x\n", i, tmp);
if ((tmp & PORT_SCR_STAT_DET_MASK) == PORT_SCR_STAT_DET_PHYRDY)
uc_priv->link_port_map |= (0x01 << i);
}
不过需要注意的是,这里修改过寄存器后,linux下的 sata speed 也被限制到了 gen2, 如果只想在 uboot下限制 speed ,加载硬盘里的内核之后,可以在 执行 bootm命令之前将寄存器修改回来。
diff --git a/cmd/bootm.c b/cmd/bootm.c
index c3a0634..7d1c292 100644
--- a/cmd/bootm.c
+++ b/cmd/bootm.c
@@ -8,6 +8,7 @@
* Boot support
*/
#include <common.h>
+#include <asm/io.h>
#include <bootm.h>
#include <command.h>
#include <environment.h>
@@ -90,6 +91,14 @@ static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc,
int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
+#ifdef CONFIG_TARGET_YY_XXXXXX
+ /* do not limit sata speed any more */
+ writel(0x301, 0x320012c);
+ udelay(1000);
+ writel(0x300, 0x320012c);
+ udelay(1000);
+#endif
+