LWN:MAX_ORDER 带来的麻烦!

关注了就能看到更多这么棒的文章哦~

The trouble with MAX_ORDER

By Jonathan Corbet
January 1, 2024
ChatGPT translation
https://lwn.net/Articles/956321/

或许人们认为关于定义整数常量值的一个很简单宏可能没有太多可说的。但内核似乎不是这样。对 MAX_ORDER 定义的更改带来了许多随之而来的影响,清理这个改动的任务尚未完成。因此,也许有必要对 MAX_ORDER 进行一番了解。

与 Linux 内核最早的版本里其他部分一样,内存管理也是很简单的实现,主要用来做单个页面的跟踪和管理。然而,到了 1994 年左右,随着内存大小的增加和内核的复杂化,很明确需要能处理较大块的页面。1994 年 4 月的 1.1.0 发布包含了内核的“伙伴分配器(buddy allocator)”的雏形,它以二的幂次方 size 的 block 作为单位来跟踪和分配页面。

随之而来的是“order(阶)”的概念,它只是内存块中页面数的二进制对数。阶为 0 的块就是单一 page,阶为 1 的块包含两个 page,依此类推。在 1.1.0 中,不同阶的内存块被保存在单独的列表中,有一个宏(NR_MEM_LISTS)描述了有多少个这样的列表。最初它被赋值为 6,这意味着可以管理的最大内存块是 order 为 5 的 block,也就是 32 个页面。1997 年 1 月的 2.1.23 发布里增加了AP1000 CPU的特殊情况支持,该 CPU 需要能够分配 8MB(阶为 11)的内存块;如果内核为该体系架构来构建的话,则将 NR_MEM_LISTS 设置为 12。

在 2.3.27(1999 年 11 月)中, NR_MEM_LISTS 得到了一个新的名字 — MAX_ORDER — 并对除 AP1000 外的所有情况都设置为 10。对 AP1000 的支持最终在 2000 年 2.3.42 中被移除,但调整 MAX_ORDER 来适应特定体系架构的做法变得越来越普遍。MAX_ORDER 的默认值现在可以在不同体系结构之间有很大的变化;在大多数系统上默认为 11。因此,在这些系统上,页面可以以 order 为 0 到 10 的内存块作为分配单位。

MAX_ORDER 目前的一个有趣之处是,按照迄今为止的描述,它实际上并不是最大 order;如果 MAX_ORDER 为 11,则可以分配的最大阶为 10。2023 年 3 月,Kirill Shutemov 决定解决这个不一致性,因为他注意到 MAX_ORDER 的一些代码中存在误解含义而导致的 bug;于是生成了这一系列补丁,修复了九个不同地方的此类 bug,包括了一个长期存在的bug,位于软盘驱动程序中。

然而,工作并没有就此结束;在这一系列的最后,Shutemov 重新定义了MAX_ORDER的含义:分配可以达到的最大 order。因此,MAX_ORDER 现在通常默认为十就导致内核(仍然)维护 11 个空闲块列表。当时,对于这一变化大部分反馈都积极接受,尽管 Mel Gorman 担心这一改动可能会导致 stable kernel 分支出现问题。David Laight 建议更改 MAX_ORDER 的名称将有助于防止这些问题,但是这个建议被忽略了,Shutemov 的一系列补丁在 2023 年 6 月的 6.4 版本中合并。

当时似乎问题已经解决。然而,在接下来的九月底,Paolo Bonzini 指出三个改动都是与 MAX_ORDER 改动同时开发的,它们仍在使用旧的含义。这些改动在编写时是正确的,但在 MAX_ORDER 更改后就出现问题了,但没有人注意到。近两个月后,Mike Snitzer 发送了一个拉取请求,其中包含了对其中一个 bug 的修复,该错误是由于为 6.5 合并的 dm-crypt 目标更改引入的。人们发现那些 out-of-tree 的代码比如 backport 代码就可能会被这一改动悄悄地破坏 — 这是在考虑 MAX_ORDER 改动时没有人提出的一个担忧。

这个错误导致 Linus Torvalds 质疑是否应该进行这个更改。他建议在没有强力理由需要保持这一改动的情况下,干脆撤销掉;他后来补充道:

啊。我看了一下引出这个改动的 commit,我真的认为“如果这是 24 年历史的结果,那么它并不是一件大事”。

与语义变更对 backport 的必然出现的问题相比(在这个合并窗口已经导致了问题),我仍然认为这一切很可能是一个错误。

他还说,与 MAX_ORDER 相关的错误通常不容易通过测试发现,因为很少会分配最大尺寸的内存块。

Shutemov 回应道,他在那个系列中修复的 bug 只是进入主线的并且从未被发现过的 bug;“我个人因 MAX_ORDER-1 的事情花了一些时间调试”。 Shutemov 接着说,真正的错误在于(正如 Laight 所指出的)保留了 MAX_ORDER 名称而改变其语义:“只要将其重命名为 MAX_PAGE_ORDER 或类似的东西就会提醒那些尚未推到 upstream 的代码”。他随后提交了另一个补丁,添加了一个新的符号 NR_ORDERS ,定义为 MAX_ORDER+1 。Torvalds 同意这一更改,但坚持认为 MAX_ORDER 的名称需要改掉以避免将来出现问题。

在十二月底,Shutemov 发布了两个新的补丁进行这些更改。其中第一个引入了新名称(现在是 NR_PAGE_ORDERS ),描述了页面分配器支持的分配 order。第二个然后将 MAX_ORDER 重命名为 MAX_PAGE_ORDER ,结果是任何使用 MAX_ORDER 的外部代码现在将无法编译。这一变更应该防止 dm-crypt bug 的重复;它还应该防止 MAX_ORDER 的错误进入稳定的内核。

这些补丁似乎可能在 6.8 合并窗口打开后被合入,这将结束内核中 MAX_ORDER 的漫长存在历史。这个故事的教训是名称确实很重要;错误的名称可能导致产生不正确的代码。同样重要的是,名称的含义不应该在没有引起可能受影响代码的注意的情况下被更改。如果一个名称不对,它可能也完全应该继续保留。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

format,png

/* * iford.dtsi- Sigmastar * * Copyright (c) [2019~2020] SigmaStar Technology. * * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License version 2 for more details. * */ #include <generated/autoconf.h> #include "../../../../drivers/sstar/include/iford/irqs.h" #include "../../../../drivers/sstar/include/iford/gpio.h" #include <dt-bindings/interrupt-controller/irq.h> #include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/input/input.h> #include <linux/kconfig.h> / { cpus { #address-cells = <1>; #size-cells = <0>; cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a32"; clock-frequency = <1000000000>; clocks = <&CLK_cpu_pll>; reg = <0x0>; operating-points-v2 = <&cpu0_opp_table>; }; #ifdef CONFIG_SMP cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a32"; clock-frequency = <1000000000>; clocks = <&CLK_cpu_pll>; reg = <0x1>; #if CONFIG_ENABLE_METHOD_PSCI enable-method = "psci"; #endif }; #endif }; cpu0_opp_table: opp_table0 { compatible = "operating-points-v2"; opp-shared; opp00 { opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <910000 890000 910000>; status = "ok"; }; }; xtal: oscillator { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <24000000>; }; #if CONFIG_ARM_PSCI psci { compatible = "arm,psci-1.0"; method = "smc"; }; #endif aliases { console = &uart0; serial0 = &uart0; serial1 = &uart1; serial2 = &fuart; serial3 = &pm_fuart; serial4 = &pm_fuart1; }; #ifdef CONFIG_OPTEE firmware { optee { compatible = "linaro,optee-tz"; method = "smc"; #interrupt-cells = <3>; interrupt-parent = <&gic>; interrupts = <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>; }; }; #endif soc { compatible = "simple-bus"; interrupt-parent = <&sstar_main_intc>; #address-cells = <1>; #size-cells = <1>; ranges; gic: gic@16000000 { compatible = "arm,gic-v3"; #interrupt-cells = <3>; #address-cells = <1>; #size-cells = <1>; interrupt-controller; interrupt-parent = <&gic>; redistributor-stride = <0x0 0x20000>; #redistributor-regions = <1>; reg = <0x16000000 0x20000>, <0x16040000 0x80000>; }; sstar_main_intc: sstar_main_intc { compatible = "sstar,main-intc"; #interrupt-cells = <3>; #address-cells = <1>; #size-cells = <1>; interrupt-parent=<&gic>; interrupt-controller; }; sstar_pm_main_intc: sstar_pm_main_intc { compatible = "sstar,pm-main-intc"; #interrupt-cells = <1>; interrupt-parent=<&sstar_main_intc>; interrupt-controller; interrupts = <GIC_SPI INT_IRQ_IRQ_FRM_PM IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_IRQ_IRQ_FRM_PM IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; sstar_pm_gpi_intc: sstar_pm_gpi_intc { compatible = "sstar,pm-gpi-intc"; #interrupt-cells = <1>; interrupt-parent=<&sstar_main_intc>; interrupt-controller; interrupts = <GIC_SPI INT_IRQ_PM_SLEEP IRQ_TYPE_LEVEL_HIGH>; }; sstar_gpi_intc: sstar_gpi_intc { compatible = "sstar,gpi-intc"; #interrupt-cells = <1>; interrupt-parent=<&sstar_main_intc>; interrupt-controller; interrupts = <GIC_SPI INT_IRQ_GPI_OUT IRQ_TYPE_LEVEL_HIGH>; }; arch_timer { compatible = "arm,cortex-a32-timer", "arm,armv8-timer"; interrupt-parent=<&gic>; interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>, <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>; clock-frequency = <6000000>; /* arch_timer must use clock-frequency*/ }; pmu { compatible = "arm,cortex-a53-pmu"; interrupt-parent=<&gic>; interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>; }; clks: clocks{ #address-cells = <1>; #size-cells = <1>; ranges; }; cpufreq { compatible = "sstar,infinity-cpufreq"; clocks = <&CLK_sar>; status = "ok"; }; miu { compatible = "sstar,miu"; interrupts=<GIC_SPI INT_IRQ_MIU IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; light_misc_control { compatible = "sstar,light_misc_control"; lightsensor-i2c = <0>; ir-ctrlmode = /bits/ 8 <0>; // 0:GPIO 1:PWM default is 0 ir-pad = <PAD_PM_PSPI0_INT>; //ir-pad = /bits/ 64 <8 41666 11249>; // <pwm_channel> <period> <duty> ircut-pad = <PAD_PM_GPIO9 PAD_PM_GPIO10>; status = "ok"; }; mmu { compatible = "sstar,mmu"; interrupts=<GIC_SPI INT_IRQ_MMU IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; /* timer_clockevent: timer@1F006040 { compatible = "sstar,piu-clockevent"; reg = <0x1F006040 0x100>; interrupts=<GIC_SPI INT_FIQ_TIMER_0 IRQ_TYPE_LEVEL_HIGH>; clocks = <&CLK_xtali_12m>; }; */ uart0: uart0@1F221000 { compatible = "sstar,uart"; reg = <0x1F221000 0x100>, <0x1F220E00 0x100>; interrupts= <GIC_SPI INT_IRQ_FUART0 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_IRQ_FUART0_MERGE IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_IRQ_FUART0_MERGE IRQ_TYPE_LEVEL_HIGH>; #if !(defined(CONFIG_SS_DUALOS) || defined(CONFIG_OPTEE)) dma-enable; #endif rx_fifo_level = <0>; tx_fifo_level = <0>; digmux = <0>; clocks = <&CLK_fuart0>, <&CLK_mcu>; status = "ok"; }; uart1: uart1@1F221200 { compatible = "sstar,uart"; reg = <0x1F221200 0x100>, < 0x1F221C00 0x100>; interrupts= <GIC_SPI INT_IRQ_FUART1 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_IRQ_FUART1_MERGE IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_IRQ_FUART1_MERGE IRQ_TYPE_LEVEL_HIGH>; #if !(defined(CONFIG_SS_DUALOS) || defined(CONFIG_OPTEE)) dma-enable; #endif #if defined(CONFIG_PM_MCU_USE_UART1) no-suspend; #endif rx_fifo_level = <0>; tx_fifo_level = <0>; digmux = <3>; clocks = <&CLK_fuart1>, <&CLK_mcu>; status = "ok"; }; fuart: fuart@1F220400 { compatible = "sstar,uart"; reg = <0x1F220400 0x100>, <0x1F220600 0x100>; interrupts= <GIC_SPI INT_IRQ_FUART IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_IRQ_FUART_MERGE IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_IRQ_FUART_MERGE IRQ_TYPE_LEVEL_HIGH>; #if !(defined(CONFIG_SS_DUALOS) || defined(CONFIG_OPTEE)) dma-enable; #endif #if defined(CONFIG_PM_MCU_USE_FUART) no-suspend; #endif sctp_enable = <0>; rx_fifo_level = <0>; tx_fifo_level = <0>; digmux = <1>; clocks = <&CLK_fuart>, <&CLK_mcu>; status = "ok"; }; pm_fuart: pm_fuart@1F006C00 { compatible = "sstar,uart"; reg = <0x1F006C00 0x100>, <0x1F006E00 0x100>; interrupt-parent = <&sstar_pm_main_intc>; interrupts= <INT_PMSLEEP_IRQ_PM_FUART>, <INT_PMSLEEP_IRQ_PM_FUART_MERGE>, <INT_PMSLEEP_IRQ_PM_FUART_MERGE>; #if !(defined(CONFIG_SS_DUALOS) || defined(CONFIG_OPTEE)) dma-enable; #endif sctp_enable = <0>; rx_fifo_level = <0>; tx_fifo_level = <0>; clocks = <&CLK_pm_fuart0>; status = "okay"; }; pm_fuart1: pm_fuart1@1F00A400 { compatible = "sstar,uart"; reg = <0x1F00A400 0x100>, <0x1F00A600 0x100>; interrupt-parent = <&sstar_pm_main_intc>; interrupts= <INT_PMSLEEP_IRQ_PM_FUART1>, <INT_PMSLEEP_IRQ_PM_FUART1_MERGE>, <INT_PMSLEEP_IRQ_PM_FUART1_MERGE>; #if !(defined(CONFIG_SS_DUALOS) || defined(CONFIG_OPTEE)) dma-enable; #endif sctp_enable = <0>; rx_fifo_level = <0>; tx_fifo_level = <0>; clocks = <&CLK_pm_fuart1>; status = "okay"; }; dla { compatible = "sstar,dla"; interrupts = <GIC_SPI INT_IRQ_DLA_TOP_0 IRQ_TYPE_LEVEL_HIGH>; clocks = <&CLK_ipupll_clk>, <&CLK_ipu>, <&CLK_ipuff>; status = "ok"; }; bdma0 { compatible = "sstar,bdma0"; interrupts = <GIC_SPI INT_IRQ_BDMA IRQ_TYPE_LEVEL_HIGH>; reg = <0x1F200400 0x80>; clocks = <&xtal>; status = "ok"; }; bdma1 { compatible = "sstar,bdma1"; interrupts = <GIC_SPI INT_IRQ_BDMA IRQ_TYPE_LEVEL_HIGH>; reg = <0x1F200480 0x80>; clocks = <&xtal>; status = "ok"; }; bdma2 { compatible = "sstar,bdma2"; interrupts = <GIC_SPI INT_IRQ_BDMA IRQ_TYPE_LEVEL_HIGH>; reg = <0x1F200500 0x80>; clocks = <&xtal>; status = "ok"; }; bdma8 { compatible = "sstar,bdma8"; interrupts = <GIC_SPI INT_IRQ_PM_BDMA IRQ_TYPE_LEVEL_HIGH>; reg = <0x1F008A00 0x80>; clocks = <&xtal>; status = "ok"; }; /* bdma9 { compatible = "sstar,bdma9"; interrupts = <GIC_SPI INT_IRQ_PM_BDMA IRQ_TYPE_LEVEL_HIGH>; reg = <0x1F008A80 0x80>; clocks = <&xtal>; status = "ok"; }; */ /* xordma { compatible = "sstar,xordma"; interrupts = <GIC_SPI INT_IRQ_BDMA_3 IRQ_TYPE_LEVEL_HIGH>; reg = <0x1F200C00 0x100>,<0x1F201800 0x100>; clocks = <&xtal>; status = "ok"; }; */ #ifdef CONFIG_OPTEE tzsp { compatible = "sstar,tzsp"; interrupts = <GIC_SPI INT_FIQ_ERROR_RESP IRQ_TYPE_EDGE_RISING>; status = "ok"; }; tzsp_dla { compatible = "sstar,tzsp_dla"; interrupt-parent=<&gic>; interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>; }; tzimi { compatible = "sstar,tzimi"; interrupts = <GIC_SPI INT_IRQ_TZIMI IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; tzemi { compatible = "sstar,tzemi"; interrupts = <GIC_SPI INT_IRQ_TZEMI IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; #endif fsp-qspi0 { compatible = "sstar,fsp-qspi"; reg = <0x1F201A00 0x200>, <0x1F201C00 0x200>; clocks = <&CLK_fsp_qspi>, <&CLK_spi_nonpm>, <&CLK_spi_synth_pll>; cs-num = <2>; cs-mode = <0>; //cs-ext = <PAD_GPIO0>; engine = <0>; dma = <1>; status = "ok"; }; nandflash0 { compatible = "sstar-nandflash"; engine = <0>; cs-select = <0>; fcie-interface = <0>; status = "ok"; }; #if IS_ENABLED(CONFIG_SSTAR_NOR) norflash0 { compatible = "sstar-norflash"; engine = <0>; cs-select = <0>; status = "ok"; }; /* norflash1 { compatible = "sstar-norflash"; engine = <0>; cs-select = <2>; status = "ok"; }; */ #endif #if IS_ENABLED(CONFIG_SSTAR_MSPI) spi@1f222000 { compatible = "sstar,mspi"; mspi-group = <0>; #ifdef CONFIG_CAM_CLK camclk = <CAMCLK_mspi0>; #else clocks = <&CLK_mspi0>; #endif reg = <0x1F222000 0x200>; #address-cells = <1>; #size-cells = <0>; interrupts = <GIC_SPI INT_IRQ_MSPI_0 IRQ_TYPE_LEVEL_HIGH>; #if !defined(CONFIG_SS_DUALOS) dma-enable; #endif cs-num = <2>; //cs-ext = <PAD_UNKNOWN>; //4to3-mode; //clk-out-mode = <27000000>; status = "ok"; #ifdef CONFIG_SS_GYRO_TRANSFER_SPI gyro@0 { compatible = "sstar,gyro_spi"; devid = <0>; reg = <0x0>; spi-max-frequency = <7000000>; }; #endif #ifdef CONFIG_SPI_SPIDEV spidev0@0 { compatible = "lwn,bk4"; spi-max-frequency = <2000000>; reg = <0>; }; spidev1@1 { compatible = "lwn,bk4"; spi-max-frequency = <2000000>; reg = <1>; }; #endif }; #endif #if IS_ENABLED(CONFIG_SSTAR_PSPI) pspi: spi@1F003200 { compatible = "sstar,pspi"; reg = <0x1F003200 0x200>; #address-cells = <1>; #size-cells = <0>; interrupts = <GIC_SPI INT_IRQ_PSPI02HOST IRQ_TYPE_LEVEL_HIGH>; clocks = <&CLK_pm_pspi0>; #ifdef CONFIG_SPI_SLAVE pspi-slave; ready-gpios = <&gpio PAD_GPIO1 0>; #endif dma-enable; group = <1>; cs-num = <1>; status = "okay"; #ifdef CONFIG_SPI_SLAVE slave@0 { compatible = "ge,achc"; reg = <0>; }; #else spidev1@0 { compatible = "ge,achc"; reg = <0>; }; #endif }; #endif #if IS_ENABLED(CONFIG_SSTAR_I2C) i2c0: i2c@1f222800 { compatible = "sstar,i2c"; reg = <0x1F222800 0x200>; #address-cells = <1>; #size-cells = <0>; interrupts = <GIC_SPI INT_IRQ_MIIC IRQ_TYPE_LEVEL_HIGH>; clocks = <&CLK_miic0>; #if !defined(CONFIG_SS_DUALOS) dma-enable; #endif group = <0>; #ifdef CONFIG_SS_GYRO_TRANSFER_I2C speed = <600000>; #else speed = <200000>;//if u want set tSU/tHD, do not set 0, tSU = (t-su-* / i2c-srcclk)S, tHD = (t-hd-* / i2c-srcclk)S #endif t-su-sta = <0>; t-hd-sta = <0>; t-su-sto = <0>; t-hd-sto = <0>; //1->open drain; 2->open drain + one push; 3->open drain + one push + clock push; 4->push-pull output-mode = <4>; status = "ok"; #ifdef CONFIG_SS_GYRO_TRANSFER_I2C gyro@d0 { compatible = "sstar,gyro"; devid = <0>; #ifdef CONFIG_SS_GYRO_CHIP_ICM40607 reg = <0x69>; #endif #ifdef CONFIG_SS_GYRO_CHIP_ICM42607 reg = <0x68>; #endif #ifdef CONFIG_SS_GYRO_CHIP_ICG20660 reg = <0x68>; #endif }; #endif }; #endif emac0: emac0 { compatible = "sstar-emac"; interrupts = <GIC_SPI INT_IRQ_EMAC IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_FIQ_LAN_ESD IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_IRQ_EMAC_SCATTER IRQ_TYPE_LEVEL_HIGH>; clocks = <&CLK_emac_ahb>; reg = <0x1F2A2000 0x800>, <0x1F304200 0x600>, <0x1F2A3000 0x600>; // reg = <0x1F2A2000 0x800>, <0x1F304200 0x600>, <0x00000000 0x000>; pad = <0x1F203C38 0x0001 0x0001>; // pad selection from 0x0001 bus-mode = <1>;//1:MII 2:RMII phy-handle = <&phy0>; cpu-affinity = <0>; //0:single cpu 1:multi cpu status = "ok"; mdio-bus@emac0 { phy0: ethernet-phy@0 { // phy-mode = "rmii"; phy-mode = "mii"; }; }; }; #if IS_ENABLED(CONFIG_SSTAR_SDMMC) #ifdef CONFIG_SSTAR_SELECT_EMMC sstar_sdmmc0: sstar_sdmmc0 { compatible = "sstar,sdmmc"; bus-width = <4>; max-frequency = <48000000>; non-removable; //broken-cd; cap-mmc-highspeed; //sd-uhs-sdr50; //sd-uhs-sdr104; //sd-uhs-ddr50; //cap-sdio-irq; no-sdio; no-sd; //no-mmc; //reg = <0x1F008400 0x200>; reg = <0x1F282600 0x200>; pll-reg = <0x1F283200 0x200>; //cifd-reg = <0x1F008600 0x200>; cifd-reg = <0x1F282800 0x200>; //pwr-save-reg = <0x1F008800 0x200>; pwr-save-reg = <0x1F282A00 0x200>; ip-order = /bits/ 8 <0>; pad-order = /bits/ 8 <0>; //pad-order = /bits/ 8 <1>; trans-mode = /bits/ 8 <1>; // 0:dma 1:adma default is 1 fake-cdz = /bits/ 8 <0>; rev-cdz = /bits/ 8 <0>; //cdz-pad = <PAD_PM_SD_CDZ>; //pwr-pad = <PAD_FUART_RTS>; pwr-on-delay = <1>; pwr-off-delay = <30>; //sdio-use-1bit = /bits/ 8 <0>; cifd-mcg-off = /bits/ 8 <0>; // mcg on/off in cifd support-cmd23 = /bits/ 8 <1>; clk-driving = <1>; cmd-driving = <1>; data-driving = <1>; en-clk-phase = /bits/ 8 <0>; //0/1 rx-clk-phase = <0>; //0-3 tx-clk-phase = <0>; //0-3 en-eight-phase = /bits/ 8 <0>; //0/1 rx-eight-phase = /bits/ 8 <0>; //0/1 tx-eight-phase = /bits/ 8 <0>; //0/1 interrupts = <GIC_SPI INT_IRQ_SD IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_IRQ_SDIO IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "mie0_irq", "mie1_irq"; clocks = <&CLK_sd>, <&CLK_pm_sdio>, <&CLK_mcu_pm>; clock-names = "clk_sdmmc0", "clk_sdmmc1", "pm_mcu_sdmmc1"; status = "ok"; }; sstar_sdmmc1: sstar_sdmmc1 { compatible = "sstar,sdmmc"; bus-width = <4>; max-frequency = <50000000>; //non-removable; //broken-cd; cap-mmc-highspeed; cap-sd-highspeed; //sd-uhs-sdr50; //sd-uhs-sdr104; //sd-uhs-ddr50; cap-sdio-irq; //no-sdio; //no-sd; no-mmc; reg = <0x1F008400 0x200>; //reg = <0x1F282600 0x200>; pll-reg = <0x1F283400 0x200>; cifd-reg = <0x1F008600 0x200>; //cifd-reg = <0x1F282800 0x200>; pwr-save-reg = <0x1F008800 0x200>; //pwr-save-reg = <0x1F282A00 0x200>; ip-order = /bits/ 8 <1>; pad-order = /bits/ 8 <0>; trans-mode = /bits/ 8 <1>; // 0:dma 1:adma default is 1 cifd-mcg-off = /bits/ 8 <0>; // mcg on/off in cifd support-runtime-pm = /bits/ 8 <0>; // sd/sdio runtime-pm default disable support-cmd23 = /bits/ 8 <1>; fake-cdz = <0>; rev-cdz = /bits/ 8 <0>; cdz-pad = <PAD_PM_SDIO_INT>; pwr-pad = <PAD_PM_GPIO12>; //cdz-pad = <PAD_SD0_CDZ>; //pwr-pad = <PAD_PM_GPIO11>; pwr-on-delay = <1>; pwr-off-delay = <30>; sdio-use-1bit = /bits/ 8 <0>; clk-driving = <1>; cmd-driving = <1>; data-driving = <1>; en-clk-phase = /bits/ 8 <0>; //0/1 rx-clk-phase = <0>; //0-3 tx-clk-phase = <0>; //0-3 en-eight-phase = /bits/ 8 <0>; //0/1, only support:000,001,010,011,100 rx-eight-phase = /bits/ 8 <0>; //0/1 tx-eight-phase = /bits/ 8 <0>; //0/1 interrupts = <GIC_SPI INT_IRQ_SDIO IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_FIQ_PAD2SDIO_SD_CDZ IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "mie1_irq", "cdz_slot1_irq"; //interrupts = <GIC_SPI INT_IRQ_SD IRQ_TYPE_LEVEL_HIGH>, // <GIC_SPI INT_FIQ_SD_CDZ_0 IRQ_TYPE_LEVEL_HIGH>; //interrupt-names = "mie0_irq", "cdz_slot0_irq"; clocks = <&CLK_sd>, <&CLK_pm_sdio>, <&CLK_mcu_pm>; clock-names = "clk_sdmmc0", "clk_sdmmc1", "pm_mcu_sdmmc1"; status = "ok"; }; #else sstar_sdmmc0: sstar_sdmmc0 { compatible = "sstar,sdmmc"; bus-width = <4>; max-frequency = <50000000>; non-removable; //broken-cd; cap-mmc-highspeed; //sd-uhs-sdr50; //sd-uhs-sdr104; //sd-uhs-ddr50; //cap-sdio-irq; no-sdio; no-sd; //no-mmc; reg = <0x1F008400 0x200>; //reg = <0x1F282600 0x200>; pll-reg = <0x1F283200 0x200>; cifd-reg = <0x1F008600 0x200>; //cifd-reg = <0x1F282800 0x200>; pwr-save-reg = <0x1F008800 0x200>; //pwr-save-reg = <0x1F282A00 0x200>; ip-order = /bits/ 8 <1>; pad-order = /bits/ 8 <0>; //pad-order = /bits/ 8 <1>; trans-mode = /bits/ 8 <1>; // 0:dma 1:adma default is 1 fake-cdz = /bits/ 8 <0>; rev-cdz = /bits/ 8 <0>; //cdz-pad = <PAD_PM_SD_CDZ>; //pwr-pad = <PAD_FUART_RTS>; pwr-on-delay = <1>; pwr-off-delay = <30>; //sdio-use-1bit = /bits/ 8 <0>; cifd-mcg-off = /bits/ 8 <0>; // mcg on/off in cifd support-cmd23 = /bits/ 8 <1>; clk-driving = <1>; cmd-driving = <1>; data-driving = <1>; en-clk-phase = /bits/ 8 <0>; //0/1 rx-clk-phase = <0>; //0-3 tx-clk-phase = <0>; //0-3 en-eight-phase = /bits/ 8 <0>; //0/1, only support:000,001,010,011,100 rx-eight-phase = /bits/ 8 <0>; //0/1 tx-eight-phase = /bits/ 8 <0>; //0/1 interrupts = <GIC_SPI INT_IRQ_SD IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_IRQ_SDIO IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "mie0_irq", "mie1_irq"; clocks = <&CLK_sd>, <&CLK_pm_sdio>, <&CLK_mcu_pm>; clock-names = "clk_sdmmc0", "clk_sdmmc1", "pm_mcu_sdmmc1"; status = "ok"; }; sstar_sdmmc1: sstar_sdmmc1 { compatible = "sstar,sdmmc"; bus-width = <4>; max-frequency = <48000000>; //non-removable; //broken-cd; cap-mmc-highspeed; cap-sd-highspeed; //sd-uhs-sdr50; //sd-uhs-sdr104; //sd-uhs-ddr50; cap-sdio-irq; //no-sdio; //no-sd; no-mmc; //reg = <0x1F008400 0x200>; reg = <0x1F282600 0x200>; pll-reg = <0x1F283400 0x200>; //cifd-reg = <0x1F008600 0x200>; cifd-reg = <0x1F282800 0x200>; //pwr-save-reg = <0x1F008800 0x200>; pwr-save-reg = <0x1F282A00 0x200>; ip-order = /bits/ 8 <0>; pad-order = /bits/ 8 <0>; trans-mode = /bits/ 8 <1>; // 0:dma 1:adma default is 1 cifd-mcg-off = /bits/ 8 <0>; // mcg on/off in cifd support-runtime-pm = /bits/ 8 <0>; // sd/sdio runtime-pm default disable support-cmd23 = /bits/ 8 <1>; fake-cdz = <0>; rev-cdz = /bits/ 8 <0>; //cdz-pad = <PAD_PM_SDIO_INT>; //pwr-pad = <PAD_PM_GPIO12>; cdz-pad = <PAD_SD0_CDZ>; pwr-pad = <PAD_PM_GPIO11>; pwr-on-delay = <1>; pwr-off-delay = <30>; sdio-use-1bit = /bits/ 8 <0>; clk-driving = <1>; cmd-driving = <1>; data-driving = <1>; en-clk-phase = /bits/ 8 <0>; //0/1 rx-clk-phase = <0>; //0-3 tx-clk-phase = <0>; //0-3 en-eight-phase = /bits/ 8 <0>; //0/1 rx-eight-phase = /bits/ 8 <0>; //0/1 tx-eight-phase = /bits/ 8 <0>; //0/1 //interrupts = <GIC_SPI INT_IRQ_SDIO IRQ_TYPE_LEVEL_HIGH>, // <GIC_SPI INT_FIQ_PAD2SDIO_SD_CDZ IRQ_TYPE_LEVEL_HIGH>; //interrupt-names = "mie1_irq", "cdz_slot1_irq"; interrupts = <GIC_SPI INT_IRQ_SD IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_FIQ_SD_CDZ_0 IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "mie0_irq", "cdz_slot0_irq"; clocks = <&CLK_sd>, <&CLK_pm_sdio>, <&CLK_mcu_pm>; clock-names = "clk_sdmmc0", "clk_sdmmc1", "pm_mcu_sdmmc1"; status = "ok"; }; #endif #endif hst0to1 { compatible = "sstar,hst0to1"; // mailbox int interrupts = <GIC_SPI INT_FIQ_CPU0TO2_TOP IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; #if IS_ENABLED(CONFIG_SSTAR_RIU_DBG) riu { #address-cells = <1>; #size-cells = <1>; compatible = "sstar,riu"; ranges; status = "ok"; #if CONFIG_SSTAR_RIU_TIMEOUT timeout { reg = <0x1F000200 0x200>, <0x1F200200 0x200>, <0x1F2CE000 0x200>; interrupts = <GIC_SPI INT_FIQ_PM_XIU_TIMEOUT IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_FIQ_XIU_TIMEOUT IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI INT_FIQ_XIU_XIU_TIMEOUT IRQ_TYPE_LEVEL_HIGH>; print-on; //bug-on; status = "ok"; }; #endif #if CONFIG_SSTAR_RIU_RECORDER recorder { reg = <0x1F229600 0x200>, <0x1F229800 0x200>, <0x1F229A00 0x200>, <0x1F229C00 0x200>; interrupts = <GIC_SPI INT_IRQ_RIU_RECORDING IRQ_TYPE_LEVEL_HIGH>; clocks = <&CLK_wdma>; print-on; //bug-on; status = "ok"; }; #endif }; #endif #if IS_ENABLED(CONFIG_SSTAR_TIMER) timer0: timer0@0x1F006040 { compatible = "sstar,timer"; clocks = <&CLK_mcu_pm_p>; reg = <0x1F006040 0x40>; interrupts = <GIC_SPI INT_FIQ_TIMER IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; timer1: timer1@0x1F006080 { compatible = "sstar,timer"; clocks = <&CLK_mcu_pm_p>; reg = <0x1F006080 0x40>; interrupts = <GIC_SPI INT_FIQ_TIMER IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; timer2: timer2@0x1F0060C0 { compatible = "sstar,timer"; clocks = <&CLK_mcu_pm_p>; reg = <0x1F0060C0 0x40>; interrupts = <GIC_SPI INT_FIQ_TIMER IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; timer3: timer3@0x1F006100 { compatible = "sstar,timer"; clocks = <&CLK_mcu_pm_p>; reg = <0x1F006100 0x40>; interrupts = <GIC_SPI INT_FIQ_TIMER IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; timer4: timer4@0x1F006140 { compatible = "sstar,timer"; clocks = <&CLK_pm_timer4>; clock-on-demand; reg = <0x1F006140 0x40>; interrupts = <GIC_SPI INT_FIQ_TIMER IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; timer5: timer5@0x1F006180 { compatible = "sstar,timer"; clocks = <&CLK_pm_timer5>; clock-on-demand; reg = <0x1F006180 0x40>; interrupts = <GIC_SPI INT_FIQ_TIMER IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; timer6: timer6@0x1F0061C0 { compatible = "sstar,timer"; clocks = <&CLK_pm_timer6>; clock-on-demand; reg = <0x1F0061C0 0x40>; interrupts = <GIC_SPI INT_FIQ_TIMER IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; timer7: timer7@0x1F006440 { compatible = "sstar,timer"; clocks = <&CLK_pm_timer7>; clock-on-demand; reg = <0x1F006440 0x40>; interrupts = <GIC_SPI INT_FIQ_TIMER IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; timer8: timer8@0x1F2CDE40 { compatible = "sstar,timer"; clocks = <&CLK_mcu>; reg = <0x1F2CDE40 0x40>; interrupts = <GIC_SPI INT_FIQ_NONPM_TIMER_0 IRQ_TYPE_EDGE_RISING>; status = "ok"; }; timer9: timer9@0x1F2CDE80 { compatible = "sstar,timer"; clocks = <&CLK_mcu>; reg = <0x1F2CDE80 0x40>; interrupts = <GIC_SPI INT_FIQ_NONPM_TIMER_1 IRQ_TYPE_EDGE_RISING>; status = "ok"; }; timer10: timer10@0x1F2CDEC0 { compatible = "sstar,timer"; clocks = <&CLK_mcu>; reg = <0x1F2CDEC0 0x40>; interrupts = <GIC_SPI INT_FIQ_NONPM_TIMER_2 IRQ_TYPE_EDGE_RISING>; status = "ok"; }; timer11: timer11@0x1F2CDF00 { compatible = "sstar,timer"; clocks = <&CLK_mcu>; reg = <0x1F2CDF00 0x40>; interrupts = <GIC_SPI INT_FIQ_NONPM_TIMER_3 IRQ_TYPE_EDGE_RISING>; status = "ok"; }; #endif watchdog0 { compatible = "sstar,wdt"; clocks = <&CLK_wdt>; reg = <0x1F006000 0x40>; interrupts = <GIC_SPI INT_FIQ_WDT IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; #if defined(CONFIG_SSTAR_LH_RTOS_VIRTIO) rpmsg: rpmsg { compatible = "sstar,sstar-lh-rtos-virtio"; }; #endif aesdma { compatible = "sstar,aesdma"; interrupts=<GIC_SPI INT_IRQ_WADR_ERR IRQ_TYPE_LEVEL_HIGH>; clocks = <&CLK_aesdma>; #ifdef CONFIG_CAM_CLK camclk = <CAMCLK_aesdma>; #endif status = "ok"; }; rng { compatible = "sstar,rng"; clocks = <&CLK_miu_boot>; status = "ok"; }; gpio: gpio { compatible = "sstar,gpio"; #gpio-cells = <2>; status = "ok"; }; clkinit { compatible = "sstar,clkinit"; #ifdef CONFIG_SSTAR_CLK_PSPI_EXT clocks = <&CLK_pm_high_ext>; default-parent = <2>; #endif status = "ok"; }; #if IS_ENABLED(CONFIG_SSTAR_ADCLP) adclp0: adclp0@1f002800 { compatible = "sstar,adclp"; interrupt-parent = <&sstar_pm_main_intc>; interrupts = <INT_PMSLEEP_IRQ_SAR_KP>; reg = <0x1F002800 0x200>; clocks = <&CLK_sar>; interrupt-enable; channel = <0>; ref-voltage = <1800>; upper-bound = <0x3FF>; lower-bound = <0>; #io-channel-cells = <1>; status = "ok"; }; adclp1: adclp1@1f002800 { compatible = "sstar,adclp"; interrupt-parent = <&sstar_pm_main_intc>; interrupts = <INT_PMSLEEP_IRQ_SAR_KP>; reg = <0x1F002800 0x200>; clocks = <&CLK_sar>; interrupt-enable; channel = <1>; ref-voltage = <1800>; upper-bound = <0x3FF>; lower-bound = <0>; #io-channel-cells = <1>; status = "ok"; }; adclp2: adclp2@1f002800 { compatible = "sstar,adclp"; interrupt-parent = <&sstar_pm_main_intc>; interrupts = <INT_PMSLEEP_IRQ_SAR_KP>; reg = <0x1F002800 0x200>; clocks = <&CLK_sar>; interrupt-enable; channel = <2>; ref-voltage = <1800>; upper-bound = <0x3FF>; lower-bound = <0>; #io-channel-cells = <1>; status = "ok"; }; adclp3: adclp3@1f002800 { compatible = "sstar,adclp"; interrupt-parent = <&sstar_pm_main_intc>; interrupts = <INT_PMSLEEP_IRQ_SAR_KP>; reg = <0x1F002800 0x200>; clocks = <&CLK_sar>; interrupt-enable; channel = <3>; ref-voltage = <1800>; upper-bound = <0x3FF>; lower-bound = <0>; #io-channel-cells = <1>; status = "ok"; }; adclp4: adclp4@1f002800 { compatible = "sstar,adclp"; interrupt-parent = <&sstar_pm_main_intc>; interrupts = <INT_PMSLEEP_IRQ_SAR_KP>; reg = <0x1F002800 0x200>; clocks = <&CLK_sar>; interrupt-enable; channel = <4>; ref-voltage = <1800>; upper-bound = <0x3FF>; lower-bound = <0>; #io-channel-cells = <1>; status = "ok"; }; #endif #if IS_ENABLED(CONFIG_SSTAR_RTC) rtcpwc: rtcpwc { compatible = "sstar,rtcpwc"; reg = <0x1F006800 0x200>; interrupts=<GIC_SPI INT_IRQ_FLAG_POC IRQ_TYPE_LEVEL_HIGH>; // io0-hiz; // io2-wos = <1>; //0:CMPHL 1:CMPHL 2:CMPL 3:CMPH // io2-wos-v = <0x2 0x3>; //<vl vh> 0<vl<8 0<vh<8 // io3-pu; // offset-count = <100>; // offset-nagative; // iso-auto-regen; /* * io4 control source selection * io0/io1/io2/io3 ctrl bit0 * alarm ctrl bit1 * sw ctrl bit2 * support the combination of above ways */ io4-enable = <3>; /* * io5 control source selection * io4 ctrl bit0 * alarm ctrl bit1 * sw ctrl bit2 * support the combination of above ways */ io5-enable = <7>; // for demo board,use 3,default hight // io5-no-poweroff; // io5 keep when excute 'poweroff' use for wakeup pm51 status = "ok"; #ifdef CONFIG_SSTAR_PWC_IO_POLLING poll-interval = <10>; #endif /* CONFIG_SSTAR_PWC_IO_POLLING */ io1 { num = <1>; keycode = <KEY_WAKEUP>; #ifdef CONFIG_SSTAR_PWC_IO_POLLING debounce-interval = <10>; #endif /* CONFIG_SSTAR_PWC_IO_POLLING */ #ifdef CONFIG_SSTAR_PWC_IO_INTERRUPT interrupt-parent = <&sstar_pm_gpi_intc>; interrupts = <INT_PM_GPI_FIQ_PAD_RTC_IO1>; #endif /* CONFIG_SSTAR_PWC_IO_INTERRUPT */ }; }; #endif #if IS_ENABLED (CONFIG_SSTAR_PWM) pwm0: pwm@0x1F203200{ compatible = "sstar,pwm"; reg = <0x1F203200 0x37>; #pwm-cells = <3>; channel = <0>; group = <0>; clocks = <&CLK_pwm>; clk-select = <0>; interrupts=<GIC_SPI INT_IRQ_PWM IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; pwm1: pwm@0x1F203280 { compatible = "sstar,pwm"; reg = <0x1F203280 0x37>; #pwm-cells = <3>; channel = <1>; group = <0>; clocks = <&CLK_pwm>; clk-select = <0>; interrupts=<GIC_SPI INT_IRQ_PWM IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; pwm2: pwm@0x1F203300 { compatible = "sstar,pwm"; reg = <0x1F203300 0x37>; #pwm-cells = <3>; channel = <2>; group = <0>; clocks = <&CLK_pwm>; clk-select = <0>; interrupts=<GIC_SPI INT_IRQ_PWM IRQ_TYPE_LEVEL_HIGH>; status = "ok"; }; #endif #if IS_ENABLED(CONFIG_SSTAR_IR) ir: ir@1F007A00 { compatible = "sstar,ir"; reg = <0x1F007A00 0x200>; clocks = <&CLK_ir>; interrupts = <GIC_SPI INT_FIQ_IR IRQ_TYPE_LEVEL_HIGH>,<GIC_SPI INT_FIQ_IR_RC IRQ_TYPE_LEVEL_HIGH>; group = <0>; /* * decode mode selection * FULL 1 Format: NEC/NECX * RAW 2 Format: NEC/NECX * RC5 3 Format: RC5 * SW 4 Format: / */ mode = <2>; //choose enum rc_proto for sw mode protocol = <9>; vendor = <0x000E>; product = <0x3412>; //rc-map-table = <customer_code + command_code input_key_code> rc-map-table = //NEC Remote Control NO.1 <0x00FFA8 KEY_POWER>, <0x00FFC0 KEY_F5>, <0x00FFDD KEY_GREEN>, <0x00FF44 KEY_F19>, <0x00FFCA KEY_UP>, <0x00FFD2 KEY_DOWN>, <0x00FF99 KEY_LEFT>, <0x00FFC1 KEY_RIGHT>, <0x00FFCE KEY_ENTER>, <0x00FFCB KEY_BACK>, <0x00FF87 KEY_HOMEPAGE>, <0x00FF97 KEY_COMPOSE>, <0x00FF41 KEY_PLAYPAUSE>, <0x00FF0F KEY_F16>, <0x00FF60 KEY_F20>, <0x00FF90 KEY_VOLUMEUP>, <0x00FF98 KEY_VOLUMEDOWN>, <0x00FFD1 KEY_MUTE>, //NEC Remote Control NO.2 <0x807F46 KEY_POWER>, <0x807F50 KEY_0>, <0x807F49 KEY_1>, <0x807F55 KEY_2>, <0x807F59 KEY_3>, <0x807F4D KEY_4>, <0x807F51 KEY_5>, <0x807F5D KEY_6>, <0x807F48 KEY_7>, <0x807F54 KEY_8>, <0x807F58 KEY_9>, <0x807F47 KEY_RED>, <0x807F4B KEY_GREEN>, <0x807F57 KEY_YELLOW>, <0x807F5B KEY_BLUE>, <0x807F52 KEY_UP>, <0x807F13 KEY_DOWN>, <0x807F06 KEY_LEFT>, <0x807F1A KEY_RIGHT>, <0x807F0F KEY_ENTER>, <0x807F1F KEY_CHANNELUP>, <0x807F19 KEY_CHANNELDOWN>, <0x807F16 KEY_VOLUMEUP>, <0x807F15 KEY_VOLUMEDOWN>, <0x807F03 KEY_PAGEUP>, <0x807F05 KEY_PAGEDOWN>, <0x807F17 KEY_HOME>, <0x807F07 KEY_MENU>, <0x807F1B KEY_BACK>, <0x807F5A KEY_MUTE>, <0x807F0D KEY_RECORD>, <0x807F42 KEY_HELP>, <0x807F14 KEY_INFO>, <0x807F40 KEY_KP0>, <0x807F04 KEY_KP1>, <0x807F0E KEY_REWIND>, <0x807F12 KEY_FORWARD>, <0x807F4C KEY_ZOOM>, <0x807F02 KEY_PREVIOUSSONG>, <0x807F1E KEY_NEXTSONG>, <0x807F01 KEY_PLAY>, <0x807F1D KEY_PAUSE>, <0x807F11 KEY_STOP>, <0x807F44 KEY_AUDIO>, <0x807F56 KEY_CAMERA>, <0x807F5C KEY_CHANNEL>, <0x807F45 KEY_SLEEP>, <0x807F4A KEY_EPG>, <0x807F10 KEY_LIST>, <0x807F53 KEY_SUBTITLE>, <0x807F41 KEY_FN_F1>, <0x807F4E KEY_FN_F2>, <0x807F0A KEY_FN_F3>, <0x807F09 KEY_FN_F4>, <0x807F1C KEY_FN_F5>, <0x807F08 KEY_FN_F6>, <0x807F0B KEY_F1>, <0x807F18 KEY_F2>, <0x807F00 KEY_F3>, <0x807F0C KEY_F4>, <0x807F4F KEY_F5>, <0x807F5E KEY_F6>, <0x807F43 KEY_F7>, <0x807F5F KEY_F8>, <0x807FFE KEY_POWER2>, <0x807FFF KEY_OK>, //RC5 Remote Control <0x150C KEY_POWER>, <0x153F KEY_AUX>, <0x141D KEY_MEDIA_REPEAT>, <0x141C KEY_SHUFFLE>, <0x100D KEY_MUTE>, <0x104F KEY_F4>, <0x143F KEY_F1>, <0x112D KEY_F2>, <0x112E KEY_F3>, <0x1010 KEY_VOLUMEUP>, <0x1011 KEY_VOLUMEDOWN>, <0x1521 KEY_PREVIOUSSONG>, <0x1520 KEY_NEXTSONG>, <0x1536 KEY_PAUSE>, <0x1535 KEY_PLAY>, <0x151F KEY_BACK>, <0x151E KEY_FORWARD>, <0x1063 KEY_MAX>, <0x1040 KEY_F6>, <0x1120 KEY_CHANNELUP>, <0x1121 KEY_CHANNELDOWN>; status = "ok"; }; #endif #if IS_ENABLED(CONFIG_USB_SUPPORT) usb2phy1_utmi: utmi@0x1f284200 { compatible="syscon"; reg = <0x1f284200 0x200>; reg-io-width = <2>; }; usb2phy1_bc: bc@0x1f284400 { compatible="syscon"; reg = <0x1f284400 0x200>; reg-io-width = <2>; }; usb2phy1_usbc: usbc@0x1f284600 { compatible="syscon"; reg = <0x1f284600 0x200>; reg-io-width = <2>; }; usb2phy1_uhc: uhc@0x1f284800 { compatible="syscon"; reg = <0x1f284800 0x200>; reg-io-width = <2>; }; sstar_u2phy1: u2phy1 { compatible = "sstar, u2phy1"; syscon-utmi = <&usb2phy1_utmi>; syscon-uhc = <&usb2phy1_uhc>; syscon-usbc = <&usb2phy1_usbc>; syscon-bc = <&usb2phy1_bc>; //utmi_dp_dm_swap = <0>; #phy-cells = <0>; status = "okay"; }; #endif #if IS_ENABLED(CONFIG_USB_EHCI_HCD) sstar-ehci-1 { compatible = "sstar-ehci-1"; reg-names = "ehc_base"; reg = <0x1f284800 0x200>; syscon-utmi = <&usb2phy1_utmi>; syscon-usbc = <&usb2phy1_usbc>; syscon-bc = <&usb2phy1_bc>; clocks = <&CLK_upll_960m>; interrupts = <GIC_SPI INT_IRQ_UHC IRQ_TYPE_LEVEL_HIGH>; phys = <&sstar_u2phy1>; phy-names = "usb"; support_high_2g_access_patch; //gpio_vbus_power = <PAD_GPIO8>; status = "ok"; }; #endif #if IS_ENABLED(CONFIG_USB_SUPPORT) msb250x-udc-p0 { compatible = "sstar,msb250x-udc"; reg = <0x1f284200 0x200>, <0x1f284600 0x200>, <0x1f284a00 0x400>, <0x1f203c00 0x200>; reg-names = "utmi", "usb0", "otg", "chiptop"; interrupts = <GIC_SPI INT_IRQ_OTG IRQ_TYPE_LEVEL_HIGH>; interrupt-names = "msb250x_udc_p0"; maximum-speed = "high-speed"; ep_name = "ep0", "ep1" , "ep2", "ep3", "ep4", "ep5", "ep6"; ep_maxpkt_limit = <64>, <1024>, <1024>, <64>, <512>, <512>, <64>; ep_fifo_size = <64>, <8192>, <1024>, <64>, <512>, <512>, <64>; dma_channel_num = <7>; clocks = <&CLK_upll_960m>; status = "okay"; }; #endif }; }; &clks { #include "../../../../drivers/sstar/include/iford/reg_clks.h" #if defined(CONFIG_SSTAR_DUALOS_DRIVER) #include "iford-clks-dualos-lite.dtsi" #else #include "iford-clks.dtsi" #endif };
最新发布
10-11
int battery_type_check(int *battery_type) { int value = 0; int ret = 0; int ret_value = 0; int battery_id = 0; int battery_type_check = 0; if (batt_id == NULL) { bm_debug("[battery_type_check]: batt_id iio channel is null []\n"); *battery_type = BAT_TYPE__ATL_4400mV; battery_id = 0; return battery_id; } ret = iio_read_channel_processed(batt_id, &ret_value); if (ret < 0) bm_debug( "[battery_type_check] read channel err = %d,\n", ret); bm_debug( "[battery_type_check]: ret = %d,ret_value[%d]\n", ret, ret_value); value = ret_value; if(is_fuelgauge_apply() == true) { switch(battery_id) case 0: if (value >= BAT_TYPE_COS_4450mV_ADC_MIN && value <= BAT_TYPE_COS_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__COS_4450mV; battery_id = BAT_COS_BATT_ID; break; case 1: if (value >= BAT_TYPE_ATL_4450mV_ADC_MIN && value <= BAT_TYPE_ATL_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__ATL_4450mV; battery_id = BAT_ATL_BATT_ID; break; case 2: if (value >= BAT_TYPE_LWN_4450mV_ADC_MIN && value <= BAT_TYPE_LWN_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__LWN_4450mV; battery_id = BAT_LWN_BATT_ID; break; case 3: *battery_type = BAT_TYPE__UNKNOWN; battery_id = BAT_ENC_BATT_ID; break; default:【兼容原来的方案】 if (value >= BAT_TYPE_ATL_4450mV_ADC_MIN && value <= BAT_TYPE_ATL_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__ATL_4450mV; battery_id = BAT_ATL_BATT_ID; } else if (value >= BAT_TYPE_LWN_4450mV_ADC_MIN && value <= BAT_TYPE_LWN_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__LWN_4450mV; battery_id = BAT_LWN_BATT_ID; } else if (value >= BAT_TYPE_COS_4450mV_ADC_MIN && value <= BAT_TYPE_COS_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__COS_4450mV; battery_id = BAT_COS_BATT_ID; } else { *battery_type = BAT_TYPE__UNKNOWN; battery_id = BAT_ENC_BATT_ID; } } else { *battery_type = BAT_TYPE__UNKNOWN; battery_id = BAT_ENC_BATT_ID; } printk(KERN_ERR "[battery_type_check]: adc_value[%d], battery_type[%d], g_fg_battery_id[%d]\n", value, *battery_type, battery_id); return battery_id; }
08-21
这段代码的主要功能是检测电池类型,通过读取电池的ADC(模数转换)值来判断使用的是哪种类型的电池。以下是代码的详细解释: ### 代码功能说明: 1. **变量定义**: - `value`:存储读取到的ADC值。 - `ret`:存储读取ADC值的返回值(用于判断是否读取成功)。 - `ret_value`:从ADC通道读取的原始值。 - `battery_id`:表示电池的ID。 - `battery_type_check`:用于判断电池类型的变量。 2. **空指针检查**: 如果 `batt_id` 为 NULL,则将电池类型设置为默认值 `BAT_TYPE__ATL_4400mV`,并将 `battery_id` 设置为 0。 3. **读取ADC值**: 使用 `iio_read_channel_processed` 函数读取ADC值,并进行错误检查。 4. **电池类型判断**: 根据 `battery_id` 的值,使用 `switch-case` 结构判断电池类型。每个 `case` 对应一个电池类型,并检查ADC值是否在该类型的范围内。 5. **默认情况处理**: 如果 `battery_id` 不在预设范围内,则进入 `default` 分支,尝试匹配其他电池类型的ADC范围。 6. **日志输出**: 使用 `printk` 输出调试信息,包括ADC值、电池类型和电池ID。 ### 问题分析: 1. **语法错误**: - `switch-case` 结构的语法不正确,`case` 分支应该直接跟在 `switch` 后面,而不是嵌套在 `if` 语句中。 - `default:` 后面的冒号应该是英文冒号 `:`,而不是中文冒号 `:`。 2. **逻辑错误**: - `battery_id` 变量在 `switch-case` 结构中被用作判断条件,但它的值在代码中没有被正确更新或传递。 3. **代码结构问题**: - `switch-case` 结构应该放在 `if(is_fuelgauge_apply() == true)` 条件之外,或者需要重新设计逻辑以确保正确执行。 ### 改进后的代码: ```c int battery_type_check(int *battery_type) { int value = 0; int ret = 0; int ret_value = 0; int battery_id = 0; if (batt_id == NULL) { bm_debug("[battery_type_check]: batt_id iio channel is null []\n"); *battery_type = BAT_TYPE__ATL_4400mV; battery_id = 0; return battery_id; } ret = iio_read_channel_processed(batt_id, &ret_value); if (ret < 0) bm_debug("[battery_type_check] read channel err = %d,\n", ret); bm_debug("[battery_type_check]: ret = %d, ret_value[%d]\n", ret, ret_value); value = ret_value; if (is_fuelgauge_apply() == true) { switch (battery_id) { case 0: if (value >= BAT_TYPE_COS_4450mV_ADC_MIN && value <= BAT_TYPE_COS_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__COS_4450mV; battery_id = BAT_COS_BATT_ID; } break; case 1: if (value >= BAT_TYPE_ATL_4450mV_ADC_MIN && value <= BAT_TYPE_ATL_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__ATL_4450mV; battery_id = BAT_ATL_BATT_ID; } break; case 2: if (value >= BAT_TYPE_LWN_4450mV_ADC_MIN && value <= BAT_TYPE_LWN_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__LWN_4450mV; battery_id = BAT_LWN_BATT_ID; } break; case 3: *battery_type = BAT_TYPE__UNKNOWN; battery_id = BAT_ENC_BATT_ID; break; default: // 兼容原来的方案 if (value >= BAT_TYPE_ATL_4450mV_ADC_MIN && value <= BAT_TYPE_ATL_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__ATL_4450mV; battery_id = BAT_ATL_BATT_ID; } else if (value >= BAT_TYPE_LWN_4450mV_ADC_MIN && value <= BAT_TYPE_LWN_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__LWN_4450mV; battery_id = BAT_LWN_BATT_ID; } else if (value >= BAT_TYPE_COS_4450mV_ADC_MIN && value <= BAT_TYPE_COS_4450mV_ADC_MAX) { *battery_type = BAT_TYPE__COS_4450mV; battery_id = BAT_COS_BATT_ID; } else { *battery_type = BAT_TYPE__UNKNOWN; battery_id = BAT_ENC_BATT_ID; } break; } } else { *battery_type = BAT_TYPE__UNKNOWN; battery_id = BAT_ENC_BATT_ID; } printk(KERN_ERR "[battery_type_check]: adc_value[%d], battery_type[%d], g_fg_battery_id[%d]\n", value, *battery_type, battery_id); return battery_id; } ``` ### 代码改进说明: 1. **语法修正**: - 修复了 `switch-case` 结构的语法错误,确保每个 `case` 分支正确嵌套在 `switch` 语句中。 - 修正了 `default` 分支的冒号符号。 2. **逻辑优化**: - 确保 `battery_id` 在 `switch-case` 结构中被正确使用,并根据ADC值更新电池类型。 3. **代码结构优化**: - 保持代码结构清晰,确保 `if(is_fuelgauge_apply() == true)` 条件下的逻辑正确执行。 ### 相关问题: 1. 如何在Linux内核中实现ADC读取? 2. 如何设计电池类型的ADC阈值? 3. 如何调试和优化电池类型检测逻辑? 4. 如何处理电池类型检测中的异常情况?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值