Zram内存压缩-开机自启动配置

:pushpin:问题描述

  • 描述内容

由于手上的小米平板2是2G运存版本,使用安卓子系统应用(哔哩哔哩、网易云音乐等)时内存不太够用导致卡顿明显,于是想着配置一下虚拟内存。

网上搜索了一番,查到一些内容说ChromeOS是使用zram,而不是传统的swap分区或文件来解决小内存设备问题。自己测试了一下发现果然无法成功开启swap分区或文件,总是“ swapon failed : Invalid argument”,不知道是不是系统哪里做了限制。不过想来米板2用的eMMC存储,配置传统swap文件反而是下策,一来影响eMMC寿命,二来IO速度硬伤。而zram是采用的内存压缩方式模拟swap,虚拟出来的swap分区其实是放在内存里,更加适合移动设备。

然后手动
modprobe zram
lsblk发现多了/dev/zram,然后
echo 3G > /sys/block/zram0/disksize
mkswap /dev/zram0
swapon /dev/zram0
没有异常,接着看看结果
free -m
显示配置成功有3个G的swap,大功告成(按照1:2的预估最小压缩率的话,最小可用内存为:(2-3/2)+3=3.5G,实际运行时压缩率应该会更好)。打开安卓子系统应用,卡顿现象大为改善。

网上搜索又发现Crosh其实有预设好的脚本命令来配置的,并且开机自启动。于是在crash输入:
swap enable 3000
没有异常,然后重启,结果并没有自动配置。查找发现,实现该自启动的为文件/etc/init/swap.conf,内容:
exec /usr/share/cros/init/swap.sh start
于是在crash进行手动开启:
swap start
结果提示无法写入/proc/sys/vm/min_filelist_kbytes,文件不存在,额。。。
找到命令脚本源文件/usr/share/cros/init/swap.sh,发现报错来自里面start函数开头
echo "${MIN_FILELSIT_DEFAULT_VALUE_KB}" > "${MIN_FILELIST_SPECIAL_FILE}"
分析发现里面用到的很多路径都在系统里没有,再看源文件开头
# Copyright 2016 The ChromiumOS Authors
。。。
不知道是不是fydeOS并没有更新这些脚本命令。没办法,只好自己搞定开机自启动。新建/etc/init/swap_zarm.conf文件,参照预设脚本,加入:

start on started system-services
script
  modprobe zram || logger -t "swap_zram" "modprobe zram failed (compiled?)"
  echo 3G > /sys/block/zram0/disksize || logger -t "swap_zram" "failed to set zram size"
  mkswap /dev/zram0 || logger -t "swap_zram" "mkswap /dev/zram0 failed"
  tries=0
  while [ "${tries}" -le 10 ]; do
    swapon /dev/zram0 && break
    : $(( tries += 1 ))
    logger -t "swap_zram" "swapon /dev/zram0 failed, try ${tries}"
    sleep 0.1
  done
end script

总结:后来去看了一下最新的ChromeOS,貌似swap相关的init文件差异很大,一下子还没弄清楚它现在是怎么处理的。希望FydeOs也能完善一下相关的内容,毕竟及时是4G以上内存,相信很多人在重载使用是还是会觉得内存不足,而zram是在不加物理运存的情况下改善内存情况的一种很好的方式。

:computer:系统与设备信息

  • 硬件与系统配置:小米平板2
    • 处理器:Intel ATOM X5-Z8500
    • 显卡:Intel HD Graphic
    • RAM(运行内存):2G
    • 存储容量:16G
    • FydeOS版本:FydeOS for PC v17.1

这个机不是很多人魔改自己加内存的么,有4G内存现在的安卓子系统就足够用了,不太会卡顿,换安卓11后就可能不够了。fydeos官方说的就是至少4G内存,再怎么虚拟内存都会消耗其他资源,zram也会消耗cpu耗电,不如加上一点内存省得顾此失彼的。
另外有现成的自启动,论坛有人发过,搜auto应该可以搜到。

现在手上的机器还没魔改过,后面是要改一下的,目前先凑合着用。此外这款机器散热是个瓶颈,估计也得改好才用得顺手。目前哔哩哔哩1080P视频可以流畅播放,但CPU温度接近60度,不能套保护壳,如果套了保护壳的话散热不畅差不多十分钟左右就会过热重启。

大佬,米板2在fydeos上的驱动全吗

目前在米板2上我是通过Brunch框架编译了Linux6.6内核来启动FydeOS的。
1.米板2的主板设计原因,内核原版gpu驱动是无法正常启动系统的(Ubuntu下可以nomodeset启动,但是FydeOS不行),所以给gpu相关的i915驱动源码打了补丁才成功启动,日志里面发现3d加速报错,但估计也用不上,其它暂未发现异常。
2.触屏驱动正常。
3.WiFi正常,但蓝牙无法打开,驱动都有,但还没找到问题所在。
4.声卡硬件是rt5659解码芯片+tfa9890功放芯片,他们单独的驱动在Linux内核里都有,但没有适配机器的Board驱动,我自己试着写了一个,目前能正常驱动喇叭外放,但3.5mm耳机孔拔插检测部分还没完成,还无法使用耳机。
5.屏幕亮度目前无法调节,一直是最亮,驱动是有识别的,但应该要打补丁。
6.电池驱动也有识别,但电量不准确。
7.音量按键、电源键正常。底部三按键有识别,返回、home键正常,但菜单键识别成“s”字母按键,按键灯不亮,不过这三键也用不太上。
8.摄像头无法工作。

2 个赞

v18似乎是默认配了zram(?),看到帖子想照着配一下发现已经有swap和zram块了233

amd64-fydeos ~ # free -h
               total        used        free      shared  buff/cache   available
Mem:           7.7Gi       1.4Gi       3.9Gi       324Mi       2.4Gi       5.8Gi
Swap:           15Gi          0B        15Gi

看样子是默认开启了2倍物理运存的zram。我还没升到18,有时间试试用18会不会有其他问题。

fydeos没有触摸屏bug(?

暂时没遇到

能开源源码吗?新主线内核有屏幕底下三个按键灯的驱动
这是我适配的源码https://github.com/Qs315490/latte_kernel_6.10
ktd2026(呼吸灯)驱动移植小米官方开源驱动
目前声音部分还是头疼,gpio注册了驱动不用,rt5659使用未初始化的延迟任务导致崩溃。主线有tfa989x驱动,补全i2c设备后驱动打的上,board驱动没头绪没办法测试。

rt5659芯片需要gpio引脚enable和reset才能正常工作,主线内核里的rt5659驱动操作引脚应该是对应设备树的情况。但英特尔平台用ACPI不用设备树,所以小米官方源码改成直接用引脚号去操作。

6.x内核里英特尔CPU Atom x5-Z8500对应的引脚驱动为 \drivers\pinctrl\intel\pinctrl-cherryview.c,有更新过,应该是兼容的,不需要改动。但是有一点,当初Linux源码3.x版本时分配gpio引脚号是从500往下的,后来更新为从500往上分配 。

分配顺序为:

西南桥0-97 => 北桥0-72 => 东桥0-26 => 东南桥0-85

EN引脚原本序号495,即西南桥92号引脚,新内核里引脚号为 500+93=593。
RESET引脚原本序号387,即北桥57号引脚,新内核里引脚号为 500+98+58=656。

//	#define CODEC_LDO_EN_GPIO 495
//	#define CODEC_RESET_GPIO 387
	#define CODEC_LDO_EN_GPIO 593
	#define CODEC_RESET_GPIO 656

英特尔atom平台有专门的音频识别ACPI驱动 80860F28 / 808622A8 (\sound\soc\intel\atom\sst\sst_acpi.c),系统启动会自动根据 \sound\soc\intel\common\soc-acpi-intel-cht-match.c 来根据声卡芯片注册相应board驱动,所以我把tfa989x驱动注册及rt5659引脚初始化都放到了soc-acpi-intel-cht-match.c里:

/********** NXP9890 amp 0 Codec **********/
#define NXP9890_ADAPTER "\\_SB_.PCI0.I2C2"

static const struct i2c_board_info NXP9890_00_board_info = {
	.type = "NXP9890_00",
	.addr = 0x37,
	.dev_name = "NXP9890_00",
};

static struct i2c_client *NXP9890_00_client;

/********** NXP9890 amp 1 Codec **********/

static const struct i2c_board_info NXP9890_01_board_info = {
	.type = "NXP9890_01",
	.addr = 0x34,
	.dev_name = "NXP9890_01",
};

static struct i2c_client *NXP9890_01_client;

static struct i2c_client *xiaomi_instantiate_i2c_client(
				char *adapter_path,
				const struct i2c_board_info *board_info)
{
	struct i2c_client *client;
	struct i2c_adapter *adap;
	acpi_handle handle;
	acpi_status status;

	status = acpi_get_handle(NULL, adapter_path, &handle);
	if (ACPI_FAILURE(status)) {
		pr_err("Error could not get %s handle\n", adapter_path);
		return ERR_PTR(-ENODEV);
	}

	adap = i2c_acpi_find_adapter_by_handle(handle);
	if (!adap) {
		pr_err("Error could not get %s adapter\n", adapter_path);
		return ERR_PTR(-ENODEV);
	}

	client = i2c_new_client_device(adap, board_info);

	put_device(&adap->dev);

	return client;
}

static int xiaomi_mipad2_add_NXP9890(void)
{
    pr_info("creating NXP9890 devices \n");

	NXP9890_00_client = xiaomi_instantiate_i2c_client(NXP9890_ADAPTER,
						       &NXP9890_00_board_info);
	if (IS_ERR(NXP9890_00_client)) {
        pr_debug("Failed NXP9890_00_client\n");
		return PTR_ERR(NXP9890_00_client);
	}

	NXP9890_01_client = xiaomi_instantiate_i2c_client(NXP9890_ADAPTER,
						       &NXP9890_01_board_info);
	if (IS_ERR(NXP9890_01_client)) {
        pr_debug("Failed NXP9890_01_client\n");
		return PTR_ERR(NXP9890_01_client);
	}

	return 0;
}

static const struct dmi_system_id xiaomi_mipad2_ids[] = {
	{
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"),
			DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"),
		},
	},
	{} /* Terminating entry */
};
static struct snd_soc_acpi_mach *rt5659_quirk(void *arg)
{
	struct snd_soc_acpi_mach *mach = arg;

	if(dmi_check_system(xiaomi_mipad2_ids)){
        xiaomi_mipad2_add_NXP9890();
        gpio_request_one(656,GPIOF_OUT_INIT_HIGH,"reset");
        gpio_request_one(593,GPIOF_OUT_INIT_HIGH,"ldo1-en");
	    msleep(500);
        bus_rescan_devices(&i2c_bus_type);
    }

	return mach;
}

加入rt5659对应board驱动(\sound\soc\intel\boards\cht_bsw_rt5659 - mipad2.c):

    {
		.id = "10EC5659",
		.drv_name = "cht-bsw-rt5659",
		.fw_filename = "intel/fw_sst_22a8.bin",
		.machine_quirk = rt5659_quirk,
	},

cht_bsw_rt5659 - mipad2.c为我在cht_bsw_rt5672.c基础上改的,只是个草稿很凌乱,勉强驱动了喇叭外放,耳机拔插部分也没处理,开了个头后面也没提起兴致继续弄,你可以参考一下。

rt5659 - mipad2.c是我在小米官方内核驱动的基础上改成能在新内核编译通过的。用主线新内核原本的,reset后芯片也能工作,但里面widget的route我没理顺,不好用alsamixer配置route。还有不少小米官方驱动改过的东西我也没细细去看。

tfa989x的,因为有两个外放喇叭,要处理一下dapm_widget命名冲突才能同时注册两个dai_link,我也还没弄。

一并传上alsamixer的ucm配置HiFi-NEW.conf。

以上,希望对你有所帮助。

soc-acpi-intel-cht-match - mipad2.c (8.5 KB)
cht_bsw_rt5659 - mipad2.c (26.1 KB)
rt5659 - mipad2.c (138.6 KB)
rt5659 - mipad2.h (62.2 KB)
tfa989x.c (16.4 KB)
HiFi-NEW.conf (5.1 KB)

1 个赞

HiFi-NEW.conf文件该放在哪个目录下,我这边补完驱动后 aplay -l 命令没有列出声卡

# lsmod|grep snd
snd_soc_tfa989x        20480  0
snd_soc_sst_cht_bsw_rt5659    24576  0
snd_seq_dummy          12288  0
snd_hrtimer            12288  1
snd_seq                98304  7 snd_seq_dummy
snd_seq_device         16384  1 snd_seq
snd_sof_acpi_intel_byt    20480  0
snd_sof_acpi           16384  1 snd_sof_acpi_intel_byt
snd_sof_intel_atom     20480  1 snd_sof_acpi_intel_byt
snd_sof               249856  3 snd_sof_intel_atom,snd_sof_acpi,snd_sof_acpi_intel_byt
snd_sof_utils          16384  1 snd_sof
snd_sof_xtensa_dsp     12288  1 snd_sof_acpi_intel_byt
snd_hdmi_lpe_audio     36864  1
snd_intel_sst_acpi     16384  0
snd_soc_acpi_intel_match   106496  2 snd_sof_acpi_intel_byt,snd_intel_sst_acpi
snd_soc_acpi           16384  3 snd_sof_intel_atom,snd_soc_acpi_intel_match,snd_intel_sst_acpi
snd_intel_sst_core     69632  1 snd_intel_sst_acpi
snd_soc_rt5659        196608  0
snd_soc_sst_atom_hifi2_platform   118784  1 snd_intel_sst_core
snd_intel_dspcfg       20480  2 snd_sof_acpi_intel_byt,snd_intel_sst_acpi
snd_soc_rl6231         16384  1 snd_soc_rt5659
snd_soc_core          417792  5 snd_sof,snd_soc_rt5659,snd_soc_sst_atom_hifi2_platform,snd_soc_sst_cht_bsw_rt5659,snd_soc_tfa989x
snd_compress           24576  1 snd_soc_core
snd_pcm_dmaengine      16384  1 snd_soc_core
snd_pcm               192512  9 snd_sof,snd_compress,snd_soc_rt5659,snd_hdmi_lpe_audio,snd_soc_sst_atom_hifi2_platform,snd_soc_core,snd_sof_utils,snd_soc_sst_cht_bsw_rt5659,snd_pcm_dmaengine
snd_timer              49152  3 snd_seq,snd_hrtimer,snd_pcm
snd                   131072  13 snd_seq,snd_seq_device,snd_sof,snd_timer,snd_compress,snd_hdmi_lpe_audio,snd_soc_sst_atom_hifi2_platform,snd_soc_core,snd_pcm
soundcore              16384  1 snd
# aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: Audio [Intel HDMI/DP LPE Audio], device 0: HdmiLpeAudio [Intel HDMI/DP LPE Audi]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: Audio [Intel HDMI/DP LPE Audio], device 1: HdmiLpeAudio [Intel HDMI/DP LPE Audi]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: Audio [Intel HDMI/DP LPE Audio], device 2: HdmiLpeAudio [Intel HDMI/DP LPE Audi]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
# cat /proc/asound/cards 
 0 [Audio          ]: HdmiLpeAudio - Intel HDMI/DP LPE Audio
                      Intel HDMI/DP LPE Audio
# ls /sys/class/sound/
card0  controlC0  pcmC0D0p  pcmC0D1p  pcmC0D2p  seq  timer

不同alsa版本的文件位置好像有差异,在/usr/share/alsa/ucm或/usr/share/alsa/ucm2目录下。

我这边是根据日志文件提示,在/usr/share/alsa/ucm2目录下新建目录cht-bsw-rt5659。

--/usr/share/alsa/ucm2
----cht-bsw-rt5659
------cht-bsw-rt5659.conf
------HiFi.conf

cht-bsw-rt5659.conf内容:

Syntax 2

SectionUseCase."HiFi" {
	File "HiFi.conf"
	Comment "Default"
}

HiFi.conf内容:

SectionVerb {

    EnableSequence [

	    # media mixer settings
	    #   compress
	    cset "name='media0_in Gain 0 Switch' on"
	    cset "name='media0_in Gain 0 Volume' 0"

	    #   normal
	    cset "name='media1_in Gain 0 Switch' on"
	    cset "name='media1_in Gain 0 Volume' 0"
	    #   swm loopback
	    cset "name='media2_in Gain 0 Switch' off"
	    cset "name='media2_in Gain 0 Volume' 0%"
	    #   deep buffer
	    cset "name='media3_in Gain 0 Switch' on"
	    cset "name='media3_in Gain 0 Volume' 0"

	    cset "name='media0_out mix 0 media0_in Switch' on"
	    cset "name='media0_out mix 0 media1_in Switch' on"
	    cset "name='media0_out mix 0 media2_in Switch' off"
	    cset "name='media0_out mix 0 media3_in Switch' on"

	    cset "name='media1_out mix 0 media0_in Switch' off"
	    cset "name='media1_out mix 0 media1_in Switch' off"
	    cset "name='media1_out mix 0 media2_in Switch' off"
	    cset "name='media1_out mix 0 media3_in Switch' off"

	    cset "name='pcm0_in Gain 0 Switch' on"
	    cset "name='pcm0_in Gain 0 Volume' 0"

	    cset "name='pcm1_in Gain 0 Switch' off"
	    cset "name='pcm1_in Gain 0 Volume' 0%"

	    # codec0_out settings (used if SSP2 is connected)
	    cset "name='codec_out0 mix 0 codec_in0 Switch' off"
	    cset "name='codec_out0 mix 0 codec_in1 Switch' off"
	    cset "name='codec_out0 mix 0 media_loop1_in Switch' off"
	    cset "name='codec_out0 mix 0 media_loop2_in Switch' off"
	    cset "name='codec_out0 mix 0 pcm0_in Switch' on"
	    cset "name='codec_out0 mix 0 pcm1_in Switch' off"
	    cset "name='codec_out0 mix 0 sprot_loop_in Switch' off"
	    cset "name='codec_out0 Gain 0 Switch' on"
	    cset "name='codec_out0 Gain 0 Volume' 6"

	    # modem_out settings (used if SSP0 is connected)
	    cset "name='modem_out mix 0 codec_in0 Switch' off"
	    cset "name='modem_out mix 0 codec_in1 Switch' off"
	    cset "name='modem_out mix 0 media_loop1_in Switch' off"
	    cset "name='modem_out mix 0 media_loop2_in Switch' off"
	    cset "name='modem_out mix 0 pcm0_in Switch' on"
	    cset "name='modem_out mix 0 pcm1_in Switch' off"
	    cset "name='modem_out mix 0 sprot_loop_in Switch' off"
	    cset "name='modem_out Gain 0 Switch' on"
	    cset "name='modem_out Gain 0 Volume' 0"

	    # input settings

	    # input used when SSP2 is connected
	    cset "name='codec_in0 Gain 0 Switch' on"
	    cset "name='codec_in0 Gain 0 Volume' 0"

	    # input used when SSP0 is connected
	    cset "name='modem_in Gain 0 Switch' on"
	    cset "name='modem_in Gain 0 Volume' 0"

	    # pcm1_out settings
	    cset "name='pcm1_out mix 0 codec_in0 Switch' on"
	    cset "name='pcm1_out mix 0 modem_in Switch' on"
	    cset "name='pcm1_out mix 0 codec_in1 Switch' off"
	    cset "name='pcm1_out mix 0 media_loop1_in Switch' off"
	    cset "name='pcm1_out mix 0 media_loop2_in Switch' off"
	    cset "name='pcm1_out mix 0 pcm0_in Switch' off"
	    cset "name='pcm1_out mix 0 pcm1_in Switch' off"
	    cset "name='pcm1_out mix 0 sprot_loop_in Switch' off"

	    cset "name='pcm1_out Gain 0 Switch' on"
	    cset "name='pcm1_out Gain 0 Volume' 0"

	    # disable codec_out1
	    cset "name='codec_out1 mix 0 codec_in0 Switch' off"
	    cset "name='codec_out1 mix 0 codec_in1 Switch' off"
	    cset "name='codec_out1 mix 0 media_loop1_in Switch' off"
	    cset "name='codec_out1 mix 0 media_loop2_in Switch' off"
	    cset "name='codec_out1 mix 0 pcm0_in Switch' off"
	    cset "name='codec_out1 mix 0 pcm1_in Switch' off"
	    cset "name='codec_out1 mix 0 sprot_loop_in Switch' off"
	    cset "name='codec_out1 Gain 0 Switch' off"
	    cset "name='codec_out1 Gain 0 Volume' 0%"

	    # disable codec_in1
	    cset "name='codec_in1 Gain 0 Switch' off"
	    cset "name='codec_in1 Gain 0 Volume' 0%"

	    # disable all loops
	    cset "name='media_loop1_out mix 0 codec_in0 Switch' off"
	    cset "name='media_loop1_out mix 0 codec_in1 Switch' off"
	    cset "name='media_loop1_out mix 0 media_loop1_in Switch' off"
	    cset "name='media_loop1_out mix 0 media_loop2_in Switch' off"
	    cset "name='media_loop1_out mix 0 pcm0_in Switch' off"
	    cset "name='media_loop1_out mix 0 pcm1_in Switch' off"
	    cset "name='media_loop1_out mix 0 sprot_loop_in Switch' off"

	    cset "name='media_loop2_out mix 0 codec_in0 Switch' off"
	    cset "name='media_loop2_out mix 0 codec_in1 Switch' off"
	    cset "name='media_loop2_out mix 0 media_loop1_in Switch' off"
	    cset "name='media_loop2_out mix 0 media_loop2_in Switch' off"
	    cset "name='media_loop2_out mix 0 pcm0_in Switch' off"
	    cset "name='media_loop2_out mix 0 pcm1_in Switch' off"
	    cset "name='media_loop2_out mix 0 sprot_loop_in Switch' off"

	    cset "name='sprot_loop_out mix 0 codec_in0 Switch' off"
	    cset "name='sprot_loop_out mix 0 codec_in1 Switch' off"
	    cset "name='sprot_loop_out mix 0 media_loop1_in Switch' off"
	    cset "name='sprot_loop_out mix 0 media_loop2_in Switch' off"
	    cset "name='sprot_loop_out mix 0 pcm0_in Switch' off"
	    cset "name='sprot_loop_out mix 0 pcm1_in Switch' off"
	    cset "name='sprot_loop_out mix 0 sprot_loop_in Switch' off"
	    
		cset "name='DAC1 Playback Volume' 6"
    ]

	DisableSequence [

	]
}

SectionDevice."Speaker".0 {
	Value {

	}

	EnableSequence [

	]
	DisableSequence [

	]
}

我在snd_cht_mc_probe函数里放了不少打印debug,你可以搜索日志文件查看确认一下声卡是否注册成功或者在哪一步出错,如果声卡注册成功,日志里应该会报cht-bsw-rt5659.conf文件不存在及要求的文件路径。

    pr_info("rt5659 mach pdev name %s\n", pdev->name);

    pr_info("rt5659 mach id %s\n", mach->id);
    pr_info("rt5659 mach drv_name %s\n", mach->drv_name);
    pr_info("rt5659 mach fw_filename %s\n", mach->fw_filename);

    dev_dbg(&pdev->dev, "rt5659 mach test 0\n");

想起一个可能导致声卡注册失败的情形,我的做法是在系统匹配声卡型号前初始化tfa9890及rt5659,然后延时,这样确保在声卡注册probe时两个芯片已经正常工作。

if(dmi_check_system(xiaomi_mipad2_ids)){
        xiaomi_mipad2_add_NXP9890();
        gpio_request_one(656,GPIOF_OUT_INIT_HIGH,"reset");
        gpio_request_one(593,GPIOF_OUT_INIT_HIGH,"ldo1-en");
	    msleep(500);
        bus_rescan_devices(&i2c_bus_type);
    }

而你的代码是单独在一个模块去做这一部分,我猜Intel SST模块的运行应该在该模块之前,正常情况下声卡注册失败会继续重试,在声卡芯片正常工作后就能注册上。但是,snd_cht_mc_probe函数里有一个修复acpi_dev_name的部分,把dai_link的codec默认名i2c-10EC5659:00修复成实际的HID(米板2的是10EC5659:01)。

	strcpy(drv->codec_name, RT5659_I2C_DEFAULT);

	/* find index of codec dai */
	for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) {
		if (cht_dailink[i].codecs->name &&
		    !strcmp(cht_dailink[i].codecs->name, RT5659_I2C_DEFAULT)) {
			dai_index = i;
			break;
		}
	}

	/* fixup codec name based on HID */
	adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1);
	if (adev) {
		snprintf(drv->codec_name, sizeof(drv->codec_name),
			 "i2c-%s", acpi_dev_name(adev));
		cht_dailink[dai_index].codecs->name = drv->codec_name;
	}
	acpi_dev_put(adev);

这段代码在第一次尝试注册,由于tfa9890还没正常工作,声卡注册失败,但是它仍然会把默认的dai_link的codec默认名i2c-10EC5659:00修改掉,导致第二次尝试注册时,无法找到rt5659对应dai_link的index,而修改index 0的dai_link的codec名,从而声卡注册失败。

另外,soc-acpi-intel-cht-match.c里,10EC5659部分建议放在808622A8前面。如果误配置CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH,则无法匹配到rt5659。

#if IS_ENABLED(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH)
	/*
	 * This is always last in the table so that it is selected only when
	 * enabled explicitly and there is no codec-related information in SSDT
	 */
	{
		.id = "808622A8",
		.drv_name = "bytcht_nocodec",
		.fw_filename = "intel/fw_sst_22a8.bin",
		.board = "bytcht_nocodec",
	},
#endif
	{
		.id = "10EC5659",
		.drv_name = "cht-bsw-rt5659",
		.fw_filename = "intel/fw_sst_22a8.bin",
	},
	{},

还有一个tfa989x的widget命名冲突问题也会导致声卡注册失败,你代码里直接就两个一起注册了,注册阶段就会失败的,而不是仅仅工作一个,建议先注释掉一个调试。

	{
		.name = "rt5659_AIF2-TFA989x_Speaker_L",
		.stream_name = "aif2-spk_l",
		.dpcm_playback = 1,
		.dpcm_capture = 1,
		SND_SOC_DAILINK_REG(rt5659_aif2_cpu, spk_l_codec),
		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
			SND_SOC_DAIFMT_CBS_CFS,
		.c2c_params = nxp_tfa989x_params,
        .num_c2c_params = 1,
	},{
		.name = "rt5659_AIF2-TFA989x_Speaker_R",
		.stream_name = "aif2-spk_r",
		.dpcm_playback = 1,
		.dpcm_capture = 1,
		SND_SOC_DAILINK_REG(rt5659_aif2_cpu, spk_r_codec),
		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
			SND_SOC_DAIFMT_CBS_CFS,
		.c2c_params = nxp_tfa989x_params,
        .num_c2c_params = 1,
	},

现在主线里tfa989x驱动没考虑多个芯片共存的情况,你的代码是两个芯片共用同一个驱动,音频流建立的route从HiFi Playback进来,HiFi Playback系统会自动加dailink前缀,但是后面的AIFINL,AIFINR,Amp Input,AMPE,OUT都会同时存在两个。要么复杂些加一套自适应前缀,要么直接复制一份代码文件改掉widget名,两个单独驱动与芯片一一对应。

static const struct snd_soc_dapm_widget tfa989x_dapm_widgets[] = {
	SND_SOC_DAPM_OUTPUT("OUT"),
	SND_SOC_DAPM_SUPPLY("POWER", TFA989X_SYS_CTRL, TFA989X_SYS_CTRL_PWDN, 1, NULL, 0),
	SND_SOC_DAPM_OUT_DRV("AMPE", TFA989X_SYS_CTRL, TFA989X_SYS_CTRL_AMPE, 0, NULL, 0),

	SND_SOC_DAPM_MUX("Amp Input", SND_SOC_NOPM, 0, 0, &chsa_mux),
	SND_SOC_DAPM_AIF_IN("AIFINL", "HiFi Playback", 0, SND_SOC_NOPM, 0, 0),
	SND_SOC_DAPM_AIF_IN("AIFINR", "HiFi Playback", 1, SND_SOC_NOPM, 0, 0),
};

static const struct snd_soc_dapm_route tfa989x_dapm_routes[] = {
	{"OUT", NULL, "AMPE"},
	{"AMPE", NULL, "POWER"},
	{"AMPE", NULL, "Amp Input"},
	{"Amp Input", "Left", "AIFINL"},
	{"Amp Input", "Right", "AIFINR"},
};

另外,由于米板2是通过rt5659间接连接tfa9890,tfa989x需要配置一下set_fmt接口,不然音频格式解码不了。

/* Params masks */
#define TFA98XX_FORMAT_MASK		(0x7)
#define TFA98XX_FORMAT_LSB		(0x4)
#define TFA98XX_FORMAT_MSB		(0x2)

static int tfa989x_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
	struct snd_soc_component *component = codec_dai->component;
	//struct tfa989x *tfa989x = snd_soc_component_get_drvdata(component);
	u16 val;

	pr_debug("\n");
    pr_info("tfa989x received fmt: %d\n",fmt);

	/* set master/slave audio interface */
	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBS_CFS:
		/* default value */
		break;
	case SND_SOC_DAIFMT_CBM_CFM:
	default:
		/* only supports Slave mode */
		pr_err("tfa989x: invalid DAI master/slave interface\n");
		return -EINVAL;
	}
	val = snd_soc_component_read(component, TFA989X_I2SREG);
	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		/* default value */
		break;
	case SND_SOC_DAIFMT_RIGHT_J:
		val &= ~(TFA98XX_FORMAT_MASK);
		val |= TFA98XX_FORMAT_LSB;
		break;
	case SND_SOC_DAIFMT_LEFT_J:
		val &= ~(TFA98XX_FORMAT_MASK);
		val |= TFA98XX_FORMAT_MSB;
		break;
	default:
		pr_err("tfa989x: invalid DAI interface format\n");
		return -EINVAL;
	}

	snd_soc_component_write(component, TFA989X_I2SREG, val);

	return 0;
}
/*****************************************************************************/

static const struct snd_soc_dai_ops tfa989x_dai_ops = {
	.hw_params = tfa989x_hw_params,
	.set_fmt   = tfa989x_set_dai_fmt,
};

tfa989x - mipad.c (16.4 KB)

cht_bsw_rt5659.c编译错误?

  CC [M]  /home/nmsl/test/cht_bsw_rt5659.o
/home/nmsl/test/cht_bsw_rt5659.c: 在函数‘cht_aif1_hw_params’中:
/home/nmsl/test/cht_bsw_rt5659.c:199:43: 错误:implicit declaration of function ‘asoc_substream_to_rtd’; did you mean ‘snd_soc_substream_to_rtd’? [-Wimplicit-function-declaration]
  199 |         struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
      |                                           ^~~~~~~~~~~~~~~~~~~~~
      |                                           snd_soc_substream_to_rtd
/home/nmsl/test/cht_bsw_rt5659.c:199:43: 错误:initialization of ‘struct snd_soc_pcm_runtime *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
/home/nmsl/test/cht_bsw_rt5659.c:200:41: 错误:implicit declaration of function ‘asoc_rtd_to_codec’; did you mean ‘snd_soc_rtd_to_codec’? [-Wimplicit-function-declaration]
  200 |         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
      |                                         ^~~~~~~~~~~~~~~~~
      |                                         snd_soc_rtd_to_codec
/home/nmsl/test/cht_bsw_rt5659.c:200:41: 错误:initialization of ‘struct snd_soc_dai *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
/home/nmsl/test/cht_bsw_rt5659.c: 在函数‘cht_audio_init’中:
/home/nmsl/test/cht_bsw_rt5659.c:325:41: 错误:initialization of ‘struct snd_soc_dai *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
  325 |         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, 0);
      |                                         ^~~~~~~~~~~~~~~~~
/home/nmsl/test/cht_bsw_rt5659.c: 在函数‘cht_aif1_startup’中:
/home/nmsl/test/cht_bsw_rt5659.c:528:39: 错误:initialization of ‘struct snd_soc_pcm_runtime *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
  528 |     struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
      |                                       ^~~~~~~~~~~~~~~~~~~~~
/home/nmsl/test/cht_bsw_rt5659.c:529:35: 错误:implicit declaration of function ‘asoc_rtd_to_cpu’; did you mean ‘snd_soc_rtd_to_cpu’? [-Wimplicit-function-declaration]
  529 |     struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
      |                                   ^~~~~~~~~~~~~~~
      |                                   snd_soc_rtd_to_cpu
/home/nmsl/test/cht_bsw_rt5659.c:529:35: 错误:initialization of ‘struct snd_soc_dai *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]

我写的时候用6.6内核的,刚好6.7后就没了。。。

改完了原地爆炸()

[  678.578905] BUG: kernel NULL pointer dereference, address: 0000000000000000
[  678.578917] #PF: supervisor read access in kernel mode
[  678.578923] #PF: error_code(0x0000) - not-present page
[  678.578929] PGD 0 P4D 0
[  678.578941] Oops: 0000 [#1] PREEMPT SMP PTI
[  678.578952] CPU: 2 PID: 7000 Comm: insmod Tainted: G           OE      6.8.10 #27
[  678.578960] Hardware name: Xiaomi Inc Mipad2/Mipad, BIOS MIPad-P4.X64.0043.R03.1603071414 03/07/2016
[  678.578966] RIP: 0010:strcmp+0x10/0x30
[  678.578983] Code: 84 00 00 00 00 00 0f 1f 40 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 31 c0 eb 08 48 83 c0 01 84 d2 74 13 <0f> b6 14 07 3a 14 06 74 ef 19 c0 83 c8 01 c3 cc cc cc cc 31 c0 c3
[  678.578992] RSP: 0018:fffface58282f9e8 EFLAGS: 00010246
[  678.579000] RAX: 0000000000000000 RBX: ffff9a3b48f9bb40 RCX: 0000000000000027
[  678.579006] RDX: 0000000000000000 RSI: ffffffffc15b5cff RDI: 0000000000000000
[  678.579011] RBP: ffff9a3b7e2cdfb0 R08: 0000000000000000 R09: fffface58282f838
[  678.579017] R10: 0000000000000001 R11: 0000000000000001 R12: ffffffffc15b0480
[  678.579022] R13: ffff9a3b7e2cdf28 R14: ffff9a3b470e0000 R15: 0000000000000000
[  678.579028] FS:  00007efe58ad4740(0000) GS:ffff9a3bbf700000(0000) knlGS:0000000000000000
[  678.579035] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  678.579040] CR2: 0000000000000000 CR3: 000000013e1ea000 CR4: 00000000001006f0
[  678.579047] Call Trace:
[  678.579055]  <TASK>
[  678.579065]  ? __die_body+0x1f/0x70
[  678.579079]  ? page_fault_oops+0x151/0x4a0
[  678.579091]  ? fixup_exception+0x26/0x330
[  678.579102]  ? exc_page_fault+0x78/0x170
[  678.579115]  ? asm_exc_page_fault+0x26/0x30
[  678.579143]  ? strcmp+0x10/0x30
[  678.579156]  snd_cht_mc_probe+0xf4/0x420 [snd_soc_sst_cht_bsw_rt5659]
[  678.579185]  ? acpi_dev_pm_attach+0x24/0xd0
[  678.579203]  platform_probe+0x43/0xb0
[  678.579222]  really_probe+0x16c/0x3d0
[  678.579242]  ? __pfx___driver_attach+0x10/0x10
[  678.579253]  __driver_probe_device+0x78/0x160
[  678.579266]  driver_probe_device+0x1e/0xa0
[  678.579281]  __driver_attach+0xb9/0x180
[  678.579294]  ? __pfx___driver_attach+0x10/0x10
[  678.579305]  bus_for_each_dev+0x7b/0xd0
[  678.579319]  bus_add_driver+0x116/0x220
[  678.579334]  driver_register+0x60/0x120
[  678.579351]  ? __pfx_snd_cht_mc_driver_init+0x10/0x10 [snd_soc_sst_cht_bsw_rt5659]
[  678.579373]  do_one_initcall+0x48/0x310
[  678.579397]  do_init_module+0x64/0x240
[  678.579417]  load_module+0x1e2b/0x20d0
[  678.579440]  ? ima_post_read_file+0xd4/0xe0
[  678.579458]  ? init_module_from_file+0x8b/0xd0
[  678.579471]  init_module_from_file+0x8b/0xd0
[  678.579488]  idempotent_init_module+0x181/0x240
[  678.579501]  __x64_sys_finit_module+0x5b/0xb0
[  678.579511]  do_syscall_64+0x84/0x170
[  678.579527]  ? syscall_exit_to_user_mode+0x82/0x230
[  678.579541]  ? do_syscall_64+0x90/0x170
[  678.579554]  ? irqentry_exit_to_user_mode+0x77/0x220
[  678.579572]  entry_SYSCALL_64_after_hwframe+0x78/0x80
[  678.579589] RIP: 0033:0x7efe5852918d
[  678.579676] Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d 5b cc 0c 00 f7 d8 64 89 01 48
[  678.579685] RSP: 002b:00007ffedb23c428 EFLAGS: 00000246 ORIG_RAX: 0000000000000139
[  678.579696] RAX: ffffffffffffffda RBX: 0000555852096730 RCX: 00007efe5852918d
[  678.579703] RDX: 0000000000000000 RSI: 00005558506e7e79 RDI: 0000000000000003
[  678.579710] RBP: 00007ffedb23c4e0 R08: 00007efe585f6b20 R09: 0000000000004100
[  678.579719] R10: 0000555852096890 R11: 0000000000000246 R12: 00005558506e7e79
[  678.579726] R13: 0000000000000000 R14: 00005558520966f0 R15: 0000000000000000
[  678.579741]  </TASK>
[  678.579746] Modules linked in: snd_soc_sst_cht_bsw_rt5659(OE+) rfcomm snd_seq_dummy snd_hrtimer nf_conntrack_netbios_ns nf_conntrack_broadcast nft_fib_inet nft_fib_ipv4 nft_fib_ipv6 nft_fib nft_reject_inet nf_reject_ipv4 nf_reject_ipv6 nft_reject nft_ct nft_chain_nat nf_nat nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ip_set nf_tables qrtr bnep snd_sof_acpi_intel_byt snd_sof_acpi snd_sof_intel_atom snd_sof_xtensa_dsp snd_sof snd_sof_utils sunrpc brcmfmac_wcc snd_soc_tfa989x(OE) bq27xxx_battery_i2c bq25890_charger bq27xxx_battery intel_powerclamp coretemp mei_pxp mei_hdcp kvm_intel snd_intel_sst_acpi intel_rapl_msr brcmfmac snd_intel_sst_core hid_sensor_rotation kvm x86_android_tablets hid_sensor_als hid_sensor_accel_3d brcmutil gpio_keys hid_sensor_incl_3d snd_soc_sst_atom_hifi2_platform hid_sensor_gyro_3d irqbypass hid_sensor_magn_3d snd_soc_acpi_intel_match(OE) hid_sensor_trigger intel_cstate pcspkr extcon_intel_cht_wc i2c_cht_wc cfg80211 leds_cht_wcove snd_soc_acpi lpc_ich hid_sensor_iio_common snd_intel_dspcfg
[  678.579943]  industrialio_triggered_buffer snd_soc_rt5659(OE) hci_uart snd_intel_sdw_acpi kfifo_buf processor_thermal_device_pci_legacy industrialio processor_thermal_device btqca snd_soc_core mei_txe processor_thermal_wt_hint intel_xhci_usb_role_switch processor_thermal_rfim btrtl ov5693 processor_thermal_rapl snd_hdmi_lpe_audio snd_compress mei ac97_bus intel_rapl_common v4l2_cci intel_atomisp2_pm snd_pcm_dmaengine v4l2_fwnode processor_thermal_wt_req snd_seq snd_seq_device v4l2_async processor_thermal_power_floor btintel processor_thermal_mbox intel_soc_dts_iosf btbcm binfmt_misc snd_pcm videodev bluetooth mc lp855x_bl intel_hid snd_timer sparse_keymap intel_soc_pmic_bxtwc rfkill snd vfat soundcore fat int3403_thermal acpi_pad int3406_thermal dptf_power intel_int0002_vgpio int340x_thermal_zone int3400_thermal acpi_thermal_rel soc_button_array joydev loop nfnetlink zram hid_sensor_hub intel_ishtp_hid crct10dif_pclmul crc32_pclmul crc32c_intel i915 polyval_generic i2c_algo_bit drm_buddy ttm ghash_clmulni_intel
[  678.580136]  hid_multitouch sha512_ssse3 drm_display_helper intel_ish_ipc mmc_block sha256_ssse3 wdat_wdt sha1_ssse3 intel_ishtp i2c_hid_acpi cec sdhci_acpi spi_pxa2xx_platform video sdhci wmi i2c_hid mmc_core pwm_lpss_platform pwm_lpss dw_dmac ip6_tables ip_tables i2c_dev fuse
[  678.580205] Unloaded tainted modules: snd_soc_sst_cht_bsw_rt5659(OE):1 [last unloaded: snd_soc_sst_cht_bsw_rt5659(OE)]
[  678.580229] CR2: 0000000000000000
[  678.580271] ---[ end trace 0000000000000000 ]---
[  678.580286] RIP: 0010:strcmp+0x10/0x30
[  678.580300] Code: 84 00 00 00 00 00 0f 1f 40 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 f3 0f 1e fa 31 c0 eb 08 48 83 c0 01 84 d2 74 13 <0f> b6 14 07 3a 14 06 74 ef 19 c0 83 c8 01 c3 cc cc cc cc 31 c0 c3
[  678.580310] RSP: 0018:fffface58282f9e8 EFLAGS: 00010246
[  678.580320] RAX: 0000000000000000 RBX: ffff9a3b48f9bb40 RCX: 0000000000000027
[  678.580327] RDX: 0000000000000000 RSI: ffffffffc15b5cff RDI: 0000000000000000
[  678.580334] RBP: ffff9a3b7e2cdfb0 R08: 0000000000000000 R09: fffface58282f838
[  678.580341] R10: 0000000000000001 R11: 0000000000000001 R12: ffffffffc15b0480
[  678.580348] R13: ffff9a3b7e2cdf28 R14: ffff9a3b470e0000 R15: 0000000000000000
[  678.580355] FS:  00007efe58ad4740(0000) GS:ffff9a3bbf700000(0000) knlGS:0000000000000000
[  678.580364] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  678.580372] CR2: 0000000000000000 CR3: 000000013e1ea000 CR4: 00000000001006f0

可能涉及一些别的相关代码变动吧。我这边6.6内核正常编译, Qs315490他在6.10内核也正常。6.7以上还改了啥我没详细关注了 :joy: