From 7825407dbf0d143b0ee2538d9821594103693654 Mon Sep 17 00:00:00 2001 From: linmin Date: Fri, 27 Dec 2024 16:54:16 +0800 Subject: [PATCH 216/222] release-1230 Changelogs: 1.fix:improve numa-node-id of each module 2.fix:npu die1 clock miss 3.feat:clk support set default cpu freq 4.fix:dsp pm devfreq bug fix 5.feat:fix bug for z530 reboot Strange noise 6.feat:fix 96k palyback error 7.fix:Resolve the issue of abnormal stack in audio. 8.fix:buffer overflow by print info 9.feat:change mode 0660 10.fix:7702 interleave can not display issue 11.feat:Select cipher as default 12.feat:adapt eth dly params to 7702 interleave dts. 13.fix:Delete HDMI Audio error printing. 14.fix:fix the DSP issue of perf function on die1. 15.chore:disable IPA adjust with target 16.feat:hdmi support 2880x1800@90 output. 17.feat:audio perf for rtc processing 18.fix: npu devfeq bug fix 19.feat: DMA memcopy kernel driver. 20.feat:add interleave dts 21.fix:fix the issue of no pcm node on die1. 22.feat:modify sdio's delay to adapt to z530. 23.fix:DSP driver add switch for perf function. 24.fix:NPU driver add switch for perf function. 25.fix:fix the issue of audio recording. 26.feat:adapt eth driver to board z530. 27.feat:support z530 board 28.fix:audio driver add 24 bits support. 29.feat:Add API for remapping malloc buffer 30.fix : remove error message when try lock failed Changelogs: 31.fix:adjust HDMI phy voltage. 32.feat:audio add sof func Signed-off-by: linmin --- arch/riscv/boot/dts/eswin/Makefile | 5 +- arch/riscv/boot/dts/eswin/eic7700-d314.dts | 335 ++++ arch/riscv/boot/dts/eswin/eic7700-evb-a2.dts | 10 +- arch/riscv/boot/dts/eswin/eic7700-evb-a3.dts | 3 +- arch/riscv/boot/dts/eswin/eic7700-evb.dts | 10 +- .../dts/eswin/eic7700-hifive-premier-p550.dts | 10 +- .../boot/dts/eswin/eic7700-som260-a1.dtsi | 724 ++++++++ arch/riscv/boot/dts/eswin/eic7700-som314.dtsi | 688 ++++++++ arch/riscv/boot/dts/eswin/eic7700-z530.dts | 198 +++ .../boot/dts/eswin/eic7702-evb-a1-d0.dts | 10 +- .../boot/dts/eswin/eic7702-evb-a1-d1.dts | 10 +- .../dts/eswin/eic7702-evb-a1-interleave.dts | 1560 +++++++++++++++++ arch/riscv/boot/dts/eswin/eic7702-evb-a1.dts | 18 +- .../boot/dts/eswin/eic770x-ooptable.dtsi | 185 ++ .../dts/eswin/eswin-win2030-arch-d2d.dtsi | 18 +- .../boot/dts/eswin/eswin-win2030-arch.dtsi | 27 +- .../dts/eswin/eswin-win2030-die0-noc.dtsi | 5 + .../dts/eswin/eswin-win2030-die0-soc.dtsi | 218 ++- .../dts/eswin/eswin-win2030-die1-noc.dtsi | 6 +- .../dts/eswin/eswin-win2030-die1-soc.dtsi | 182 +- arch/riscv/configs/eic7700_defconfig | 5 +- arch/riscv/configs/eic7702_defconfig | 5 +- arch/riscv/configs/win2030_defconfig | 1 + drivers/clk/eswin/clk-win2030.c | 41 +- drivers/clocksource/timer-eswin.c | 97 +- drivers/dma-buf/dma-heap.c | 1 + drivers/gpu/drm/eswin/Makefile | 2 +- drivers/gpu/drm/eswin/dw-hdmi.c | 7 +- drivers/gpu/drm/eswin/dw-hdmi.h | 2 +- drivers/gpu/drm/eswin/dw_hdmi_audio.h | 2 +- drivers/gpu/drm/eswin/dw_hdmi_cec.c | 2 +- drivers/gpu/drm/eswin/dw_hdmi_cec.h | 2 +- drivers/gpu/drm/eswin/dw_hdmi_hdcp.c | 2 +- drivers/gpu/drm/eswin/dw_hdmi_hdcp.h | 2 +- drivers/gpu/drm/eswin/dw_hdmi_hdcp2.c | 2 +- drivers/gpu/drm/eswin/dw_hdmi_i2s_audio.c | 2 +- drivers/gpu/drm/eswin/es_dc.c | 38 +- drivers/gpu/drm/eswin/es_dc.h | 3 + drivers/gpu/drm/eswin/es_drv.c | 11 +- .../eswin/{eswin_dw_hdmi.c => es_dw_hdmi.c} | 16 +- drivers/interconnect/eswin/noc.c | 2 +- drivers/memory/eswin/Kconfig | 1 + drivers/memory/eswin/Makefile | 1 + drivers/memory/eswin/codacache/llc_spram.c | 252 ++- drivers/memory/eswin/es_dma_memcp/Kconfig | 6 + drivers/memory/eswin/es_dma_memcp/Makefile | 1 + .../memory/eswin/es_dma_memcp/es_dma_memcp.c | 604 +++++++ .../dmabuf-heap-import-helper.c | 187 ++ .../ethernet/stmicro/stmmac/dwmac-win2030.c | 87 +- drivers/regulator/es5340.c | 2 - drivers/soc/eswin/ai_driver/Kconfig | 10 + drivers/soc/eswin/ai_driver/dsp/Makefile | 4 + drivers/soc/eswin/ai_driver/dsp/dsp_main.c | 158 +- .../soc/eswin/ai_driver/dsp/dsp_platform.c | 17 +- .../soc/eswin/ai_driver/dsp/dsp_platform.h | 2 +- .../eswin/ai_driver/dsp/dsp_platform_sim.c | 2 +- drivers/soc/eswin/ai_driver/npu/Makefile | 5 +- drivers/soc/eswin/ai_driver/npu/dla_driver.h | 10 +- drivers/soc/eswin/ai_driver/npu/npu_main.c | 215 ++- drivers/soc/eswin/ai_driver/npu/nvdla_hw.c | 91 +- .../soc/eswin/ai_driver/npu/nvdla_lowlevel.h | 1 + .../soc/eswin/ai_driver/npu/user_context.c | 29 +- .../media/eswin/dewarp/vvcam_dwe_driver.c | 78 + .../os/linux/kernel/gc_hal_kernel_driver.c | 7 +- .../eswin/gc_hal_kernel_platform_win2030.c | 87 +- drivers/staging/media/eswin/vdec/hantro_dec.c | 77 + .../staging/media/eswin/venc/vc8000e_driver.c | 79 + include/linux/dmabuf-heap-import-helper.h | 2 + include/uapi/linux/dma_memcp.h | 62 + sound/soc/codecs/eswin/es8328.c | 55 +- sound/soc/codecs/eswin/es8328.h | 24 +- sound/soc/eswin/Kconfig | 7 +- sound/soc/eswin/Makefile | 2 +- sound/soc/eswin/esw-audio-proc.c | 26 +- sound/soc/eswin/esw-dai.h | 62 + sound/soc/eswin/esw-dma.c | 485 +++++ sound/soc/eswin/esw-i2s.c | 405 +++-- sound/soc/eswin/esw-i2s.h | 53 +- sound/soc/eswin/esw-sof-dai.c | 299 ++++ sound/soc/sof/Kconfig | 1 + sound/soc/sof/Makefile | 1 + sound/soc/sof/eswin/Kconfig | 34 + sound/soc/sof/eswin/Makefile | 6 + sound/soc/sof/eswin/es-common.c | 591 +++++++ sound/soc/sof/eswin/es-common.h | 137 ++ sound/soc/sof/eswin/es-sof-dsp.c | 614 +++++++ 86 files changed, 8682 insertions(+), 664 deletions(-) create mode 100644 arch/riscv/boot/dts/eswin/eic7700-d314.dts create mode 100644 arch/riscv/boot/dts/eswin/eic7700-som260-a1.dtsi create mode 100644 arch/riscv/boot/dts/eswin/eic7700-som314.dtsi create mode 100644 arch/riscv/boot/dts/eswin/eic7700-z530.dts create mode 100644 arch/riscv/boot/dts/eswin/eic7702-evb-a1-interleave.dts create mode 100644 arch/riscv/boot/dts/eswin/eic770x-ooptable.dtsi rename drivers/gpu/drm/eswin/{eswin_dw_hdmi.c => es_dw_hdmi.c} (99%) create mode 100644 drivers/memory/eswin/es_dma_memcp/Kconfig create mode 100644 drivers/memory/eswin/es_dma_memcp/Makefile create mode 100644 drivers/memory/eswin/es_dma_memcp/es_dma_memcp.c create mode 100644 include/uapi/linux/dma_memcp.h create mode 100644 sound/soc/eswin/esw-dai.h create mode 100644 sound/soc/eswin/esw-dma.c create mode 100644 sound/soc/eswin/esw-sof-dai.c create mode 100644 sound/soc/sof/eswin/Kconfig create mode 100644 sound/soc/sof/eswin/Makefile create mode 100644 sound/soc/sof/eswin/es-common.c create mode 100644 sound/soc/sof/eswin/es-common.h create mode 100644 sound/soc/sof/eswin/es-sof-dsp.c diff --git a/arch/riscv/boot/dts/eswin/Makefile b/arch/riscv/boot/dts/eswin/Makefile index b3925240449f..4f8d4275c021 100644 --- a/arch/riscv/boot/dts/eswin/Makefile +++ b/arch/riscv/boot/dts/eswin/Makefile @@ -4,5 +4,8 @@ dtb-$(CONFIG_SOC_SIFIVE) += eswin-win2030.dtb \ eic7700-evb-a2.dtb \ eic7700-evb-a3.dtb \ eic7700-hifive-premier-p550.dtb \ - eic7702-evb-a1.dtb + eic7702-evb-a1.dtb \ + eic7700-z530.dtb \ + eic7700-d314.dtb \ + eic7702-evb-a1-interleave.dtb obj-$(CONFIG_BUILTIN_DTB) += $(addsuffix .o, $(dtb-y)) diff --git a/arch/riscv/boot/dts/eswin/eic7700-d314.dts b/arch/riscv/boot/dts/eswin/eic7700-d314.dts new file mode 100644 index 000000000000..f8bfb293fcfa --- /dev/null +++ b/arch/riscv/boot/dts/eswin/eic7700-d314.dts @@ -0,0 +1,335 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree file for Eswin EIC7700 SoC. + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/dts-v1/; + +#include "eic7700-som314.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "ESWIN 7700D314"; +}; + +&pcie { + /* GPIO12 PCIE PRSNT input */ +}; + +&d0_usbdrd_dwc3_1 { + usb-hub { + gpio-hog; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio43_default>; + gpios = <&portb 11 GPIO_ACTIVE_HIGH>; + output-low; + line-name = "usb-hub-reset"; + }; +}; + +&dsi_panel { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio82_default &pinctrl_gpio85_default>; + backlight0-gpios = <&portc 18 GPIO_ACTIVE_HIGH>; + rst-gpios = <&portc 21 GPIO_ACTIVE_HIGH>; +}; + +&d0_i2s1 { + status = "okay"; + d0_i2s1_port: port { + d0_i2s1_endpoint: endpoint { + remote-endpoint = <&d0_codec0_endpoint>; + dai-format = "i2s"; + }; + }; +}; + +&d0_i2s2 { + /* connect WIFI module */ + status = "disabled"; +}; + +&d0_graphcard1 { + status = "okay"; + label = "Analog Audio"; + dais = <&d0_i2s1_port>; +}; + +&d0_graphcard2 { + status = "disabled"; +}; + +&isp_0 { + status = "disabled"; +}; + +&isp_1 { + status = "disabled"; +}; + +&sdio0 { + /* sd card */ + status = "okay"; + delay_code = <0x55>; + drive-impedance-ohm = <33>; + enable-cmd-pullup; + enable-data-pullup; + no-sdio; + no-mmc; +}; + +&sdio1 { + /* wifi module */ + status = "okay"; + delay_code = <0x29>; + drive-impedance-ohm = <33>; + enable-cmd-pullup; + enable-data-pullup; + non-removable; + keep-power-in-suspend; + no-sd; + no-mmc; + aw3155:wifi_aw3155@0 { + compatible = "aml_w1_sdio"; + reg = <0x0>; + interrupt-parent = <&porta>; + interrupts = <15 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default", "default"; + pinctrl-0 = <&pinctrl_gpio15_default>; + pinctrl-1 = <&pinctrl_gpio79_default>; + irq-gpios = <&porta 15 GPIO_ACTIVE_HIGH>; + rst-gpios = <&portc 15 GPIO_ACTIVE_HIGH>; + }; +}; + +&d0_sata { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sata_act_led_default>; +}; + +&d0_uart1 { + /* M.2 KEY E */ + status = "disabled"; +}; + +&d0_uart2 { + /* connect MCU */ + status = "okay"; +}; + +&d0_uart3 { + /* pin header mux with GPIO 92,93 */ + status = "disabled"; +}; + +&d0_uart4 { + /* unused */ + status = "disabled"; +}; + +&ssi0 { + /* pin header mux with GPIO 35,36,37,38,39,40 */ + status = "disabled"; +}; + +&ssi1 { + /* unused */ + status = "disabled"; +}; + +&d0_i2c0 { + /* codec es8388 */ + status = "okay"; + d0_es8388_0: es8388-0@11 { + compatible = "eswin,es8388"; + reg = <0x11>; + #sound-dai-cells = <0>; + eswin-plat = <2>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio0_default &pinctrl_gpio28_default>; + front-jack-gpios = <&porta 0 GPIO_ACTIVE_HIGH>; + back-jack-gpios = <&porta 28 GPIO_ACTIVE_HIGH>; + port { + d0_codec0_endpoint: endpoint { + system-clock-frequency = <12288000>; + remote-endpoint = <&d0_i2s1_endpoint>; + }; + }; + }; +}; + +&d0_i2c1 { + /* pin header mux with GPIO 46,47 */ + status = "disabled"; +}; + +&d0_i2c2 { + /* mipi dsi touch ctrl con */ + status = "disabled"; +}; + +&d0_i2c3 { + /* FUSB303B cc logic */ + status = "okay"; + fusb303b@21 { + compatible = "fcs,fusb303b"; + status = "okay"; + reg = <0x21>; + eswin,syscfg = <&d0_sys_con 0x3C0 12>; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio5_default>; + int-gpios = <&porta 5 GPIO_ACTIVE_HIGH>; + connector { + compatible = "usb-c-connector"; + label = "USB-C"; + data-role = "host"; + }; + }; + +}; + +&d0_i2c4 { + /* unused */ + status = "disabled"; +}; + +&d0_i2c5 { + /* PCA9548 */ + status = "okay"; +}; + +&d0_i2c6 { + /* unused */ + status = "disabled"; +}; + +&d0_i2c7 { + /* unused */ + status = "disabled"; +}; + +&d0_i2c8 { + /* unused */ + status = "disabled"; +}; + +&d0_i2c9 { + /* unused */ + status = "disabled"; +}; + +&d0_aon_i2c0 { + /* AT24C02C EEPROM */ + status = "okay"; + eswin,syscfg = <&d0_sys_con 0x3C0 16>; + aon_eeprom@50 { + compatible = "atmel,24c02"; + reg = <0x50>; + }; +}; + +&d0_aon_i2c1 { + /* PCA9450 & SiC451 & INA226 & PAC1934 */ + status = "okay"; + eswin,syscfg = <&d0_sys_con 0x3C0 15>; + i2c-sda-hold-time-ns = <0x40>; + pac1934:pmic@10 { + compatible = "microchip,pac1934"; + /*update all register data*/ + update_time_ms = <1000>; + eswin,chan_label = "som vdd", "soc vdd", "cpu vdd", "ddr lpvdd"; + label = "som_info"; + /*The update number of times the energy accumulates*/ + energy_acc_count = <0>; + shunt_resistors=<1 1 1 1>; + reg = <0x10>; + }; + + sys_power:ina226@44 { + compatible = "ti,ina226"; + #io-channel-cells = <1>; + label = "sys_power"; + reg = <0x44>; + shunt-resistor = <1000>; + }; + + mpq8785@12 { + compatible = "mps,mpq8785"; + reg = <0x12>; + eswin,regulator_default-microvolt=<1000000>; + eswin,regulator_label = "supply vdd1", "npu vdd1", "npu current1", "npu temperature1"; + label = "npu_vdd"; + regulators{ + npu_vcc1:npu_svcc{ + regulator-name="NPU_SVCC"; + regulator-min-microvolt=<700000>; + regulator-max-microvolt=<1100000>; + regulator-min-microamp=<20000000>; + regulator-max-microamp=<40000000>; + regulator-ov-protection-microvolt=<1100000>; + regulator-always-on; + }; + }; + }; +}; + +&pinctrl { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio6_default &pinctrl_gpio7_default &pinctrl_gpio8_default &pinctrl_gpio9_default + &pinctrl_gpio10_default &pinctrl_gpio17_default &pinctrl_gpio35_default &pinctrl_gpio36_default + &pinctrl_gpio37_default &pinctrl_gpio38_default &pinctrl_gpio39_default &pinctrl_gpio40_default + &pinctrl_gpio41_default &pinctrl_gpio46_default &pinctrl_gpio52_default + &pinctrl_gpio53_default &pinctrl_gpio64_default &pinctrl_gpio65_default &pinctrl_gpio66_default + &pinctrl_gpio67_default &pinctrl_gpio70_default &pinctrl_gpio73_default &pinctrl_gpio83_default + &pinctrl_gpio86_default &pinctrl_gpio87_default &pinctrl_gpio92_default &pinctrl_gpio93_default + &pinctrl_gpio94_default>; + + /* pin header default function for GPIO + SPI1 (CS0,SCLK,MOSI,MISO,D2,D3): GPIO 35,36,37,38,39,40 + I2C1 (SCL,SDA): GPIO 46,47 + UART3(TX,RX): GPIO 92,93 + */ +}; + +/* +GPIO USED ON CarrierBoard: + gpio0 : FP Audio Jack Sense(I), active low + gpio5 : TYPE C cc logic interrupt(I), active low + gpio11 : BT WAKE HOST(I), active low + gpio12 : PCIE present(I), active low + gpio14 : DSI FPC CON CTRL(J10&J11) + gpio15 : Wlan wake host(I), active low + gpio28 : RP audio jack sense(I), active low + gpio29 : EMMC active led ctrl(O) + + gpio43 : USB3.2 Gen1 hub Resetn(O), active low + gpio71 : CSI fpc con ctrl(O) + gpio74 : CSI fpc con ctrl(O) + gpio77 : CSI fpc con ctrl(O) + gpio76 : HOST WAKE BT(O), active low + gpio79 : WLAN POWER ON(O), active high + gpio80 : CSI fpc con ctrl(O) + gpio82 : DSI FPC CON CTRL(J10) + gpio85 : DSI FPC CON CTRL(J11) + gpio84 : GPIO LED CTRL(O), active high +*/ diff --git a/arch/riscv/boot/dts/eswin/eic7700-evb-a2.dts b/arch/riscv/boot/dts/eswin/eic7700-evb-a2.dts index 1ea82a170c60..42a2eb700568 100644 --- a/arch/riscv/boot/dts/eswin/eic7700-evb-a2.dts +++ b/arch/riscv/boot/dts/eswin/eic7700-evb-a2.dts @@ -285,6 +285,7 @@ &pcie { &d0_npu{ status = "okay"; + npu-supply=<&npu_vcc1>; }; &d0_dsp_subsys { @@ -507,7 +508,9 @@ &d0_gmac0 { rst-gpios = <&portc 30 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x290 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; - + dly-param-1000m = <0x23232323 0x800c8023 0x0c0c0c0c>; + dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; + dly-param-10m = <0 0 0>; status = "okay"; }; @@ -517,7 +520,9 @@ &d0_gmac1 { rst-gpios = <&porta 16 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x294 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; - + dly-param-1000m = <0x25252525 0x80268025 0x26262626>; + dly-param-100m = <0x48484848 0x80588048 0x58585858>; + dly-param-10m = <0 0 0>; status = "okay"; }; @@ -727,7 +732,6 @@ npu_vcc1:npu_svcc{ regulator-min-microamp=<20000000>; regulator-max-microamp=<40000000>; regulator-ov-protection-microvolt=<1100000>; - regulator-always-on; }; }; }; diff --git a/arch/riscv/boot/dts/eswin/eic7700-evb-a3.dts b/arch/riscv/boot/dts/eswin/eic7700-evb-a3.dts index 47b490f8c6c1..bfc99f105556 100644 --- a/arch/riscv/boot/dts/eswin/eic7700-evb-a3.dts +++ b/arch/riscv/boot/dts/eswin/eic7700-evb-a3.dts @@ -29,9 +29,10 @@ &d0_clock { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_gpio95_default>; cpu-voltage-gpios = <&portc 31 GPIO_ACTIVE_HIGH>; + cpu-default-frequency = ; }; -&d0_cpu_opp_table { +&cpu_opp_table { opp-1500000000 { opp-hz = /bits/ 64 ; opp-microvolt = <900000>; diff --git a/arch/riscv/boot/dts/eswin/eic7700-evb.dts b/arch/riscv/boot/dts/eswin/eic7700-evb.dts index fe56de5b1699..a6226cc932b6 100644 --- a/arch/riscv/boot/dts/eswin/eic7700-evb.dts +++ b/arch/riscv/boot/dts/eswin/eic7700-evb.dts @@ -246,6 +246,7 @@ &pcie { &d0_npu{ status = "okay"; + npu-supply=<&npu_vcc1>; }; &d0_dsp_subsys { @@ -466,7 +467,9 @@ &d0_gmac0 { rst-gpios = <&portc 30 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x290 0x3>; eswin,led-cfgs = <0x6251 0x6251 0x6251>; - + dly-param-1000m = <0x23232323 0x800c8023 0x0c0c0c0c>; + dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; + dly-param-10m = <0 0 0>; status = "okay"; }; @@ -476,7 +479,9 @@ &d0_gmac1 { rst-gpios = <&porta 16 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x294 0x3>; eswin,led-cfgs = <0x6251 0x6251 0x6251>; - + dly-param-1000m = <0x25252525 0x80268025 0x26262626>; + dly-param-100m = <0x48484848 0x80588048 0x58585858>; + dly-param-10m = <0 0 0>; status = "okay"; }; @@ -770,7 +775,6 @@ npu_vcc1:npu_svcc{ regulator-min-microamp=<20000000>; regulator-max-microamp=<40000000>; regulator-ov-protection-microvolt=<1100000>; - regulator-always-on; }; }; }; diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts index d4225cf45d5b..ca2edb1eb7e5 100644 --- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts +++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts @@ -240,6 +240,7 @@ &pcie { &d0_npu{ status = "okay"; + npu-supply=<&npu_vcc1>; }; &d0_dsp_subsys { @@ -456,6 +457,9 @@ &d0_gmac0 { rst-gpios = <&portd 10 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x290 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; + dly-param-1000m = <0x23232323 0x800c8023 0x0c0c0c0c>; + dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; + dly-param-10m = <0 0 0>; }; &d0_gmac1 { @@ -465,6 +469,9 @@ &d0_gmac1 { rst-gpios = <&portd 15 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x294 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; + dly-param-1000m = <0x25252525 0x80268025 0x26262626>; + dly-param-100m = <0x48484848 0x80588048 0x58585858>; + dly-param-10m = <0 0 0>; }; &d0_sata { @@ -838,6 +845,7 @@ gpio111 : gphy1 resern(O), active low &gpio0 { status = "okay"; }; + &dev_llc_d0{ /* apply_npu_1G_freq; */ npu-supply=<&npu_vcc1>; @@ -849,7 +857,7 @@ &d0_clock { cpu-voltage-gpios = <&portc 30 GPIO_ACTIVE_HIGH>; }; -&d0_cpu_opp_table { +&cpu_opp_table { opp-1500000000 { opp-hz = /bits/ 64 ; opp-microvolt = <900000>; diff --git a/arch/riscv/boot/dts/eswin/eic7700-som260-a1.dtsi b/arch/riscv/boot/dts/eswin/eic7700-som260-a1.dtsi new file mode 100644 index 000000000000..8975632b0325 --- /dev/null +++ b/arch/riscv/boot/dts/eswin/eic7700-som260-a1.dtsi @@ -0,0 +1,724 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree file for Eswin EIC7700 SoC. + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/dts-v1/; + +#define RTCCLK_FREQ 1000000 +#define LSPCLK_FREQ 200000000 + +/* If wanna enable ECC capability of DDR, should reserve highest zone of 1/8 all space for it */ +#define MEMORY_SIZE_H 0x4 +#define MEMORY_SIZE_L 0x0 +#define CMA_SIZE 0x20000000 + +#include "eswin-win2030-die0-soc.dtsi" +#include "eic7700-pinctrl.dtsi" +#include +#include +#include + +/* Clock frequency (in Hz) of the PCB crystal for rtcclk */ + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "ESWIN 7700S260"; + compatible = "sifive,hifive-unmatched-a00", "sifive,fu740-c000", + "sifive,fu740", "eswin,eic7700"; + + aliases { + serial0 = &d0_uart0; + ethernet0 = &d0_gmac0; + ethernet1 = &d0_gmac1; + }; + + chosen { + stdout-path = "serial0:115200n8"; + opensbi_domain_config: domain-config { + compatible = "opensbi,domain,config"; + system-suspend-test; + }; + }; + + cpus { + timebase-frequency = ; + }; + + memory@59000000 { + device_type = "memory"; + reg = <0x0 0x59000000 0x0 0x400000>; + numa-node-id = <0>; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 MEMORY_SIZE_H MEMORY_SIZE_L>; + numa-node-id = <0>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 CMA_SIZE>; + alignment = <0x0 0x1000>; + alloc-ranges = <0x0 0x80000000 MEMORY_SIZE_H MEMORY_SIZE_L>; + linux,cma-default; + }; + + npu0_reserved: sprammemory@59000000 { + no-map; + reg = <0x0 0x59000000 0x0 0x400000>; + }; + + g2d_4GB_boundary_reserved_4k { + no-map; + reg = <0x0 0xfffff000 0x0 0x1000>; + }; + + g2d_8GB_boundary_reserved_4k { + no-map; + reg = <0x1 0xfffff000 0x0 0x1000>; + }; + + g2d_12GB_boundary_reserved_4k { + no-map; + reg = <0x2 0xfffff000 0x0 0x1000>; + }; + + mmz_nid_0_part_0 { + compatible = "eswin-reserve-memory"; + reg = <0x3 0x0 0x1 0x80000000>; + no-map; + }; + }; +}; + +/**************************************************** + Carrier board device capability, need be adapted by user according to the carrier board implemented. + All of below modules are configured to okay by default, and need be reconfigured by user in dts of carrier board. + pcie + d0_sata + d0_usbdrd3_0 + d0_usbdrd3_1 + dw_hdmi + mipi csi(2 lanes) x4 + mipi dsi(4 lanes) + sdio0 + sdio1 + d0_i2c0 + d0_i2c1 + d0_i2c2 + aon_i2c0 + d0_uart0 + d0_uart1 + d0_uart2 + d0_uart4 + ssi0 + ssi1 + pwm1 + pwm2 + gpio + d0_gmac0 + d0_gmac1 +****************************************************/ + +&cpu_opp_table { + opp-1500000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <900000>; + clock-latency-ns = <70000>; + }; + opp-1600000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <900000>; + clock-latency-ns = <70000>; + }; + opp-1700000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <900000>; + clock-latency-ns = <70000>; + }; + opp-1800000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <900000>; + clock-latency-ns = <70000>; + }; +}; + +&d0_clock { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio94_default>; + cpu-voltage-gpios = <&portc 30 GPIO_ACTIVE_HIGH>; +}; + +&d0_reset { + status = "okay"; +}; + +&d0_pmu { + status = "okay"; +}; + +&ddr0 { + status = "okay"; +}; + +&ddr1 { + status = "okay"; +}; + +&smmu0 { + status = "okay"; +}; + +&smmu_pmu0 { + status = "disabled"; +}; + +&dev_foo_a { + status = "okay"; +}; + +&d0_cfg_noc { + status = "okay"; +}; + +&d0_llc_noc { + status = "okay"; + stat,0 = "TracePort:ddr0_p0_req"; + stat,1 = "TracePort:ddr1_p0_req"; + //latency,0 = "TracePort:llcnoc_trans_probe"; + //pending,0 = "TracePort:llcnoc_trans_probe"; +}; + +&d0_sys_noc { + status = "okay"; + + //eswin,DSPT-qos-owner; + //eswin,NPU-qos-owner; + //eswin,SPISLV_TBU3-qos-owner; + +#if 0 + stat,0 = "TracePort:ddr0_p1_req", + "InitFlow:mcput_snoc_mp/I/0"; + + stat,1 = "TracePort:ddr0_p2_req", + "InitFlow:dspt_snoc/I/0", + "AddrBase:0x81000000", "AddrSize:0x30", + "Opcode:RdWrLockUrg", "Status:ReqRsp", "Length:0x8000", "Urgency:0x0"; + + stat,2 = "TracePort:ddr1_p1_req", + "Status:Req", "AddrSize:0x28"; + + stat,3 = "TracePort:ddr1_p2_req"; +#else + stat,0 = "TracePort:ddr0_p1_req"; + + stat,1 = "TracePort:ddr0_p2_req"; + + stat,2 = "TracePort:ddr1_p1_req"; + + stat,3 = "TracePort:ddr1_p2_req"; +#endif + + latency,0 = "TracePort:sysnoc_trans_probe_0", "AddrSize:0x0"; + latency,1 = "TracePort:sysnoc_trans_probe_1","Mode:latency","AddrBase:0x82000000","AddrSize:0x28","Opcode:RdWr"; + //latency,2 = "TracePort:sysnoc_trans_probe_2"; + + //pending,0 = "TracePort:sysnoc_trans_probe_0"; + //pending,1 = "TracePort:sysnoc_trans_probe_1","Mode:latency","AddrBase:0x82000000","AddrSize:0x0","Opcode:RdWr"; + pending,0 = "TracePort:sysnoc_trans_probe_2", "AddrSize:0x3"; +}; + +&d0_media_noc { + status = "okay"; + + //eswin,GPU-qos-owner; + //eswin,TBU2-qos-owner; + //eswin,VC-qos-owner; + + stat,0 = "TracePort:ddr0_p3_req"; + stat,1 = "TracePort:ddr1_p3_req"; + //latency,0 = "TracePort:mnoc_trans_probe"; + //pending,0 = "TracePort:mnoc_trans_probe"; +}; + +&d0_realtime_noc { + status = "okay"; + + //eswin,TBU0-qos-owner; + //eswin,VO-qos-owner; + + stat,0 = "TracePort:ddr0_p4_req"; + stat,1 = "TracePort:ddr1_p4_req"; + //latency,0 = "TracePort:rnoc_trans_probe"; + //pending,0 = "TracePort:rnoc_trans_probe"; +}; + +&d0_noc_wdt { + status = "okay"; +}; + +&d0_ipc_scpu { + status = "okay"; +}; + +&d0_lpcpu { + status = "okay"; +}; + +&pcie { + status = "okay"; +}; + +&d0_npu{ + status = "okay"; +}; + +&d0_dsp_subsys { + status = "okay"; +}; + +&d0_dsp0 { + status = "okay"; +}; + +&d0_dsp1 { + status = "okay"; +}; + +&d0_dsp2 { + status = "okay"; +}; + +&d0_dsp3 { + status = "okay"; +}; + +&gpu0 { + status = "okay"; +}; + +&gc820 { + status = "okay"; +}; + +&vdec0 { + status = "okay"; +}; + +&venc0 { + status = "okay"; +}; + +&video_output { + status = "okay"; +}; + +&dc { + status = "okay"; +}; + +&dc_test { + status = "disabled"; +}; + +&virtual_display { + status = "okay"; +}; + +&dsi_output { + status = "okay"; +}; + +&dsi_controller { + status = "okay"; +}; + +&dsi_panel { + /* backlight0-gpios, rst-gpios */ + status = "okay"; +}; + +&dw_hdmi { + status = "okay"; + ports { + port@2 { + reg = <2>; + hdmi_in_i2s: endpoint@1 { + system-clock-frequency = <12288000>; + remote-endpoint = <&d0_i2s0_endpoint>; + }; + }; + }; +}; + +&dw_hdmi_hdcp2 { + status = "okay"; +}; + +&d0_i2s0 { + status = "okay"; + d0_i2s0_port: port { + d0_i2s0_endpoint: endpoint { + remote-endpoint = <&hdmi_in_i2s>; + dai-format = "i2s"; + }; + }; +}; + +&d0_graphcard0 { + status = "okay"; + label = "HDMI Audio"; + dais = <&d0_i2s0_port>; +}; + +&isp_0 { + status = "okay"; +}; + +&isp_1 { + status = "okay"; +}; + +&dewarp { + status = "okay"; +}; + +&mipi_dphy_rx { + status = "okay"; +}; + +&csi_dma0 { + status = "okay"; +}; + +&csi_dma1 { + status = "disabled"; +}; + +&csi2_0 { + status = "okay"; +}; + +&csi2_1 { + status = "disabled"; +}; + +&sdhci_emmc { + /* emmc */ + status = "okay"; + delay_code = <0x17>; + drive-impedance-ohm = <50>; + enable-cmd-pullup; + enable-data-pullup; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_emmc_led_control_default>; + no-sdio; + no-sd; +}; + +&sdio0 { + status = "okay"; +}; + +&sdio1 { + status = "okay"; +}; + +&d0_gmac0 { + pinctrl-names = "default"; + eswin,rgmiisel = <&pinctrl 0x290 0x3>; + eswin,led-cfgs = <0x6100 0xa40 0x420>; + status = "okay"; +}; + +&d0_gmac1 { + pinctrl-names = "default"; + eswin,rgmiisel = <&pinctrl 0x294 0x3>; + eswin,led-cfgs = <0x6100 0xa40 0x420>; + status = "okay"; +}; + +&d0_sata { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sata_act_led_default>; +}; + +&d0_usbdrd3_0 { + status = "okay"; +}; + +&d0_usbdrd_dwc3_0 { + status = "okay"; + dr_mode = "host"; + maximum-speed = "super-speed"; +}; + +&d0_usbdrd3_1 { + status = "okay"; +}; + +&d0_usbdrd_dwc3_1 { + status = "okay"; + dr_mode = "host"; + maximum-speed = "super-speed"; +}; + +&d0_dmac0 { + status = "okay"; +}; + +&d0_aon_dmac { + status = "okay"; +}; + +&d0_uart0 { + /* debug */ + status = "okay"; +}; + +&d0_uart1 { + status = "okay"; +}; + +&d0_uart2 { + status = "okay"; +}; + +&d0_uart3 { + /* no provide */ + status = "disabled"; +}; + +&d0_uart4 { + status = "okay"; +}; + +&ssi0 { + status = "okay"; +}; + +&ssi1 { + status = "disabled"; +}; + +&bootspi { + /* spi flash */ + status = "okay"; + num-cs = <1>; + cs-gpios = <&portd 0 GPIO_ACTIVE_LOW>; + wp-gpios = <&portd 4 GPIO_ACTIVE_LOW>; + spi-flash@0 { + compatible = "winbond,w25q128jw", + "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <4800000>; + rx-sample-delay-ns = <10>; + }; +}; + +&d0_mbox0 { + status = "okay"; +}; + +&d0_mbox1 { + status = "okay"; +}; + +&d0_mbox2 { + status = "okay"; +}; + +&d0_mbox3 { + status = "okay"; +}; + +&d0_mbox4 { + status = "okay"; +}; + +&d0_mbox5 { + status = "okay"; +}; + +&d0_mbox6 { + status = "okay"; +}; + +&d0_mbox7 { + status = "okay"; +}; + +&fan_control { + status = "okay"; + eswin,pwm_inverted; +}; + +&d0_i2c0 { + status = "okay"; +}; + +&d0_i2c1 { + status = "okay"; +}; + +&d0_i2c2 { + status = "okay"; +}; + +&d0_i2c3 { + /* no provide */ + status = "disabled"; +}; + +&d0_i2c4 { + /* no provide */ + status = "disabled"; +}; + +&d0_i2c5 { + /* tmp102 */ + status = "okay"; + tmp102@48 { + compatible = "ti,tmp102"; + reg = <0x48>; + label = "d0_board_tmp"; + #thermal-sensor-cells = <1>; + }; +}; + +&d0_i2c6 { + /* no provide */ + status = "disabled"; +}; + +&d0_i2c7 { + /* no provide */ + status = "disabled"; +}; + +&d0_i2c8 { + /* no provide */ + status = "disabled"; +}; + +&d0_i2c9 { + /* no provide */ + status = "disabled"; +}; + +&d0_aon_i2c0 { + status = "okay"; +}; + +&d0_aon_i2c1 { + /* pmic es5340 */ + status = "okay"; + es5340@f { + compatible = "einno,es5340"; + reg = <0xf>; + eswin,regulator_default-microvolt=<1000000>; + eswin,regulator_label = "supply vdd1", "npu vdd1", "npu current1", "npu temperature1"; + label = "npu_vdd"; + regulators{ + npu_vcc1:npu_svcc{ + regulator-name="NPU_SVCC"; + regulator-min-microvolt=<700000>; + regulator-max-microvolt=<1100000>; + regulator-min-microamp=<20000000>; + regulator-max-microamp=<40000000>; + regulator-ov-protection-microvolt=<1100000>; + regulator-always-on; + }; + }; + }; +}; + +&pwm0 { + /* fan */ + status = "okay"; +}; + +&pvt0 { + status = "okay"; +}; + +&pvt1 { + status = "okay"; +}; + +&wdt0 { + status = "disabled"; +}; + +&wdt1 { + status = "disabled"; +}; + +&wdt2 { + status = "disabled"; +}; + +&wdt3 { + status = "disabled"; +}; + +&die0_rtc { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&pinctrl { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; +&dev_llc_d0{ + /* apply_npu_1G_freq; */ + npu-supply=<&npu_vcc1>; + status = "okay"; +}; diff --git a/arch/riscv/boot/dts/eswin/eic7700-som314.dtsi b/arch/riscv/boot/dts/eswin/eic7700-som314.dtsi new file mode 100644 index 000000000000..79a885bb2c62 --- /dev/null +++ b/arch/riscv/boot/dts/eswin/eic7700-som314.dtsi @@ -0,0 +1,688 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree file for Eswin EIC7700 SoC. + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/dts-v1/; + +#define RTCCLK_FREQ 1000000 +#define LSPCLK_FREQ 200000000 + +/* If wanna enable ECC capability of DDR, should reserve highest zone of 1/8 all space for it */ +#define MEMORY_SIZE_H 0x4 +#define MEMORY_SIZE_L 0x0 +#define CMA_SIZE 0x20000000 + +#include "eswin-win2030-die0-soc.dtsi" +#include "eic7700-pinctrl.dtsi" +#include +#include + +/* Clock frequency (in Hz) of the PCB crystal for rtcclk */ + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "ESWIN 7700S314"; + compatible = "eswin,eic7700"; + + aliases { + serial0 = &d0_uart0; + ethernet0 = &d0_gmac0; + ethernet1 = &d0_gmac1; + }; + + chosen { + stdout-path = "serial0:115200n8"; + opensbi_domain_config: domain-config { + compatible = "opensbi,domain,config"; + system-suspend-test; + }; + }; + + cpus { + timebase-frequency = ; + }; + + memory@59000000 { + device_type = "memory"; + reg = <0x0 0x59000000 0x0 0x400000>; + numa-node-id = <0>; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x0 0x80000000 MEMORY_SIZE_H MEMORY_SIZE_L>; + numa-node-id = <0>; + }; + + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 CMA_SIZE>; + alignment = <0x0 0x1000>; + alloc-ranges = <0x0 0x80000000 MEMORY_SIZE_H MEMORY_SIZE_L>; + linux,cma-default; + }; + + npu0_reserved: sprammemory@59000000 { + no-map; + reg = <0x0 0x59000000 0x0 0x400000>; + }; + + g2d_4GB_boundary_reserved_4k { + no-map; + reg = <0x0 0xfffff000 0x0 0x1000>; + }; + + g2d_8GB_boundary_reserved_4k { + no-map; + reg = <0x1 0xfffff000 0x0 0x1000>; + }; + + g2d_12GB_boundary_reserved_4k { + no-map; + reg = <0x2 0xfffff000 0x0 0x1000>; + }; + + mmz_nid_0_part_0 { + compatible = "eswin-reserve-memory"; + reg = <0x3 0x0 0x1 0x80000000>; + no-map; + }; + }; +}; + +&d0_clock { + status = "okay"; +}; + +&d0_reset { + status = "okay"; +}; + +&d0_pmu { + status = "okay"; +}; + +&ddr0 { + status = "okay"; +}; + +&ddr1 { + status = "okay"; +}; + +&smmu0 { + status = "okay"; +}; + +&smmu_pmu0 { + status = "disabled"; +}; + +&dev_foo_a { + status = "okay"; +}; + +&d0_cfg_noc { + status = "okay"; +}; + +&d0_llc_noc { + status = "okay"; + stat,0 = "TracePort:ddr0_p0_req"; + stat,1 = "TracePort:ddr1_p0_req"; + //latency,0 = "TracePort:llcnoc_trans_probe"; + //pending,0 = "TracePort:llcnoc_trans_probe"; +}; + +&d0_sys_noc { + status = "okay"; + + //eswin,DSPT-qos-owner; + //eswin,NPU-qos-owner; + //eswin,SPISLV_TBU3-qos-owner; + +#if 0 + stat,0 = "TracePort:ddr0_p1_req", + "InitFlow:mcput_snoc_mp/I/0"; + + stat,1 = "TracePort:ddr0_p2_req", + "InitFlow:dspt_snoc/I/0", + "AddrBase:0x81000000", "AddrSize:0x30", + "Opcode:RdWrLockUrg", "Status:ReqRsp", "Length:0x8000", "Urgency:0x0"; + + stat,2 = "TracePort:ddr1_p1_req", + "Status:Req", "AddrSize:0x28"; + + stat,3 = "TracePort:ddr1_p2_req"; +#else + stat,0 = "TracePort:ddr0_p1_req"; + + stat,1 = "TracePort:ddr0_p2_req"; + + stat,2 = "TracePort:ddr1_p1_req"; + + stat,3 = "TracePort:ddr1_p2_req"; +#endif + + latency,0 = "TracePort:sysnoc_trans_probe_0", "AddrSize:0x0"; + latency,1 = "TracePort:sysnoc_trans_probe_1","Mode:latency","AddrBase:0x82000000","AddrSize:0x28","Opcode:RdWr"; + //latency,2 = "TracePort:sysnoc_trans_probe_2"; + + //pending,0 = "TracePort:sysnoc_trans_probe_0"; + //pending,1 = "TracePort:sysnoc_trans_probe_1","Mode:latency","AddrBase:0x82000000","AddrSize:0x0","Opcode:RdWr"; + pending,0 = "TracePort:sysnoc_trans_probe_2", "AddrSize:0x3"; +}; + +&d0_media_noc { + status = "okay"; + + //eswin,GPU-qos-owner; + //eswin,TBU2-qos-owner; + //eswin,VC-qos-owner; + + stat,0 = "TracePort:ddr0_p3_req"; + stat,1 = "TracePort:ddr1_p3_req"; + //latency,0 = "TracePort:mnoc_trans_probe"; + //pending,0 = "TracePort:mnoc_trans_probe"; +}; + +&d0_realtime_noc { + status = "okay"; + + //eswin,TBU0-qos-owner; + //eswin,VO-qos-owner; + + stat,0 = "TracePort:ddr0_p4_req"; + stat,1 = "TracePort:ddr1_p4_req"; + //latency,0 = "TracePort:rnoc_trans_probe"; + //pending,0 = "TracePort:rnoc_trans_probe"; +}; + +&d0_noc_wdt { + status = "okay"; +}; + +&d0_ipc_scpu { + status = "okay"; +}; + +&d0_lpcpu { + status = "okay"; +}; + +&pcie { + status = "okay"; +}; + +&d0_npu{ + status = "okay"; +}; + +&d0_dsp_subsys { + status = "okay"; +}; + +&d0_dsp0 { + status = "okay"; +}; + +&d0_dsp1 { + status = "okay"; +}; + +&d0_dsp2 { + status = "okay"; +}; + +&d0_dsp3 { + status = "okay"; +}; + +&gpu0 { + status = "okay"; +}; + +&gc820 { + status = "okay"; +}; + +&vdec0 { + status = "okay"; +}; + +&venc0 { + status = "okay"; +}; + +&video_output { + status = "okay"; +}; + +&dc { + status = "okay"; +}; + +&dc_test { + status = "disabled"; +}; + +&virtual_display { + status = "okay"; +}; + +&dsi_output { + status = "okay"; +}; + +&dsi_controller { + status = "okay"; +}; + +&dsi_panel { + status = "okay"; +}; + +&dw_hdmi { + status = "okay"; + ports { + port@2 { + reg = <2>; + hdmi_in_i2s: endpoint@1 { + system-clock-frequency = <12288000>; + remote-endpoint = <&d0_i2s0_endpoint>; + }; + }; + }; +}; + +&dw_hdmi_hdcp2 { + status = "okay"; +}; + +&d0_i2s0 { + status = "okay"; + d0_i2s0_port: port { + d0_i2s0_endpoint: endpoint { + remote-endpoint = <&hdmi_in_i2s>; + dai-format = "i2s"; + }; + }; +}; + +&d0_i2s1 { + status = "okay"; +}; + +&d0_i2s2 { + status = "okay"; +}; + +&d0_graphcard0 { + status = "okay"; + label = "HDMI Audio"; + dais = <&d0_i2s0_port>; +}; + +&isp_0 { + status = "okay"; +}; + +&isp_1 { + status = "okay"; +}; + +&dewarp { + status = "okay"; +}; + +&mipi_dphy_rx { + status = "disabled"; +}; + +&csi_dma0 { + status = "disabled"; +}; + +&csi_dma1 { + status = "disabled"; +}; + +&csi2_0 { + status = "disabled"; +}; + +&csi2_1 { + status = "disabled"; +}; + +&sdhci_emmc { + /* emmc */ + status = "okay"; + delay_code = <0x17>; + drive-impedance-ohm = <50>; + enable-cmd-pullup; + enable-data-pullup; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_emmc_led_control_default>; + no-sdio; + no-sd; +}; + +&sdio0 { + status = "okay"; +}; + +&sdio1 { + status = "okay"; +}; + +&d0_gmac0 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio106_default>; + rst-gpios = <&portd 10 GPIO_ACTIVE_LOW>; + eswin,rgmiisel = <&pinctrl 0x290 0x3>; + eswin,led-cfgs = <0x6100 0xa40 0x420>; + dly-param-1000m = <0x23232323 0x800c8023 0x0c0c0c0c>; + dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; + dly-param-10m = <0 0 0>; +}; + +&d0_gmac1 { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio111_default>; + rst-gpios = <&portd 15 GPIO_ACTIVE_LOW>; + eswin,rgmiisel = <&pinctrl 0x294 0x3>; + eswin,led-cfgs = <0x6100 0xa40 0x420>; + dly-param-1000m = <0x25252525 0x80268025 0x26262626>; + dly-param-100m = <0x48484848 0x80588048 0x58585858>; + dly-param-10m = <0 0 0>; +}; + +&d0_sata { + status = "okay"; +}; + +&d0_usbdrd3_0 { + status = "okay"; +}; + +&d0_usbdrd_dwc3_0 { + status = "okay"; + dr_mode = "host"; + maximum-speed = "super-speed"; +}; + +&d0_usbdrd3_1 { + status = "okay"; +}; + +&d0_usbdrd_dwc3_1 { + status = "okay"; + dr_mode = "host"; + maximum-speed = "super-speed"; +}; + +&d0_dmac0 { + status = "okay"; +}; + +&d0_aon_dmac { + status = "okay"; +}; + +&d0_uart0 { + /* debug */ + status = "okay"; +}; + +&d0_uart1 { + status = "okay"; +}; + +&d0_uart2 { + status = "okay"; +}; + +&d0_uart3 { + status = "okay"; +}; + +&d0_uart4 { + status = "okay"; +}; + +&ssi0 { + status = "okay"; +}; + +&ssi1 { + status = "okay"; +}; + +&bootspi { + /* spi flash */ + status = "okay"; + num-cs = <1>; + cs-gpios = <&portd 0 GPIO_ACTIVE_LOW>; + wp-gpios = <&portd 4 GPIO_ACTIVE_LOW>; + spi-flash@0 { + compatible = "winbond,w25q128jw", + "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <4800000>; + rx-sample-delay-ns = <10>; + }; +}; + +&d0_mbox0 { + status = "okay"; +}; + +&d0_mbox1 { + status = "okay"; +}; + +&d0_mbox2 { + status = "okay"; +}; + +&d0_mbox3 { + status = "okay"; +}; + +&d0_mbox4 { + status = "okay"; +}; + +&d0_mbox5 { + status = "okay"; +}; + +&d0_mbox6 { + status = "okay"; +}; + +&d0_mbox7 { + status = "okay"; +}; + +&fan_control { + status = "okay"; + eswin,pwm_inverted; +}; + +&d0_i2c0 { + status = "okay"; +}; + +&d0_i2c1 { + status = "okay"; +}; + +&d0_i2c2 { + status = "okay"; +}; + +&d0_i2c3 { + status = "okay"; +}; + +&d0_i2c4 { + status = "okay"; +}; + +&d0_i2c5 { + status = "okay"; +}; + +&d0_i2c6 { + status = "okay"; +}; + +&d0_i2c7 { + status = "okay"; +}; + +&d0_i2c8 { + status = "okay"; +}; + +&d0_i2c9 { + status = "okay"; +}; + +&d0_aon_i2c0 { + status = "okay"; +}; + +&d0_aon_i2c1 { + status = "okay"; +}; + +&pwm0 { + /* fan */ + status = "okay"; +}; + +&pvt0 { + status = "okay"; +}; + +&pvt1 { + status = "okay"; +}; + +&wdt0 { + status = "disabled"; +}; + +&wdt1 { + status = "disabled"; +}; + +&wdt2 { + status = "disabled"; +}; + +&wdt3 { + status = "disabled"; +}; + +&die0_rtc { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; + +&pinctrl { + status = "okay"; +}; + +/* + GPIO USED ON SOM: + gpio18 : HOST WAKE WLAN(O), active low + gpio19 : HOST WAKE BT(O), active low + gpio20 : WLAN WAKE HOST(I), active low + gpio21 : BT WAKE HOST(I), active low + gpio106 : gphy0 resern(O), active low + gpio111 : gphy1 resern(O), active low + +*/ + +&gpio0 { + status = "okay"; +}; +&dev_llc_d0{ + /* apply_npu_1G_freq; */ + npu-supply=<&npu_vcc1>; + status = "okay"; +}; + +&d0_clock { + status = "okay"; + cpu-voltage-gpios = <&portc 30 GPIO_ACTIVE_HIGH>; +}; + +&cpu_opp_table { + opp-1500000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <900000>; + clock-latency-ns = <70000>; + }; + opp-1600000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <900000>; + clock-latency-ns = <70000>; + }; + opp-1700000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <900000>; + clock-latency-ns = <70000>; + }; + opp-1800000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <900000>; + clock-latency-ns = <70000>; + }; +}; diff --git a/arch/riscv/boot/dts/eswin/eic7700-z530.dts b/arch/riscv/boot/dts/eswin/eic7700-z530.dts new file mode 100644 index 000000000000..d9dc8a8afd6a --- /dev/null +++ b/arch/riscv/boot/dts/eswin/eic7700-z530.dts @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree file for Eswin EIC7700 SoC. + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "eic7700-som260-a1.dtsi" + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "ESWIN EIC7700 Z530"; + + gpio-keys { + compatible = "gpio-keys"; + + ap_backup { + label = "ap-backup"; + linux,code = ; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio26_default>; + gpios = <&porta 26 GPIO_ACTIVE_LOW>; + }; + }; +}; + +&d0_gmac0 { + dly-param-1000m = <0x23232323 0xa0209023 0x20202020>; + dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; + dly-param-10m = <0 0 0>; +}; + +&d0_gmac1 { + dly-param-1000m = <0x00000000 0xe002e000 0x04040404>; + dly-param-100m = <0x48484848 0x80588048 0x58585858>; + dly-param-10m = <0 0 0>; +}; + + +&pcie { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio10_default>; + pci-prsnt = <&porta 10 GPIO_ACTIVE_LOW>; +}; + +&sdio0 { + /* sd card */ + delay_code = <0x3b>; + drive-impedance-ohm = <33>; + enable-cmd-pullup; + enable-data-pullup; + no-sdio; + no-mmc; +}; + +&sdio1 { + /* wifi module */ + delay_code = <0x32>; + drive-impedance-ohm = <33>; + enable-cmd-pullup; + enable-data-pullup; + keep-power-in-suspend; + non-removable; + no-sd; + no-mmc; + aw3155:wifi_aw3155@0 { + compatible = "aml_w1_sdio"; + reg = <0x0>; + interrupt-parent = <&porta>; + interrupts = <15 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default", "default"; + pinctrl-0 = <&pinctrl_gpio15_default>; + pinctrl-1 = <&pinctrl_gpio79_default>; + irq-gpios = <&porta 15 GPIO_ACTIVE_HIGH>; + rst-gpios = <&portc 15 GPIO_ACTIVE_HIGH>; + + }; +}; + +&ssi0 { + /* lora */ +}; + +&ssi1 { + /* unused */ + status = "disabled"; +}; + +&dsi_panel { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio7_default &pinctrl_gpio92_default>; + backlight0-gpios = <&porta 7 GPIO_ACTIVE_HIGH>; + rst-gpios = <&portc 28 GPIO_ACTIVE_HIGH>; +}; + +&d0_graphcard1 { + status = "okay"; + label = "Analog Audio-0"; + dais = <&d0_i2s1_port>; +}; + +&d0_graphcard2 { + status = "disabled"; +}; + +&d0_i2s1 { + status = "okay"; + d0_i2s1_port: port { + d0_i2s1_endpoint: endpoint { + remote-endpoint = <&d0_codec0_endpoint>; + dai-format = "i2s"; + }; + }; +}; + +&d0_i2s2 { + status = "disabled"; +}; + +&d0_i2c0 { + /* codec es8388 */ + d0_es8388_0: es8388-0@10 { + compatible = "eswin,es8388"; + reg = <0x10>; + #sound-dai-cells = <0>; + eswin-plat = <3>; + port { + d0_codec0_endpoint: endpoint { + system-clock-frequency = <12288000>; + remote-endpoint = <&d0_i2s1_endpoint>; + }; + }; + }; +}; + +&d0_i2c1 { + /* rtc rs4c411 & mipi dsi */ + +}; + +&d0_i2c2 { + /* touch screen*/ + gt911:touchscreen@14 { + compatible = "goodix,gt911"; + reg = <0x14>; + interrupt-parent = <&porta>; + interrupts = <0 IRQ_TYPE_EDGE_RISING>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio0_default &pinctrl_gpio92_default>; + irq-gpios = <&porta 0 GPIO_ACTIVE_HIGH>; + reset-gpios = <&portc 28 GPIO_ACTIVE_HIGH>; + }; +}; + +&d0_aon_i2c0 { + /* rk628f x2 */ + +}; + +/* GPIO Function Description + gpio0 : touch int(I) + gpio5 : 5g wake on host(I) + gpio6 : 5g disable2(O) + gpio7 : mipi dsi ctrl(O) + gpio8 : 5g disable1(O) + gpio9 : rk628 plugin detect(I) + gpio10 : pcie prsnt(I) + gpio12 : bt wake host(I) + gpio15 : wlan wake host(I) + gpio26 : ap backup(I) + gpio39 : lora busy(I) + gpio41 : host wake bt(I) + gpio70 : rk628 int(I) + gpio71 : rk628 reset(O) + gpio73 : rk628 power enable(O) + gpio74 : 5g pwren(O) + gpio76 : eth rset(O) + gpio77 : lora nreset(O) + gpio79 : m2 power on(O) + gpio80 : lora ctrl2(O) + gpio81 : lora ctrl1(O) + gpio92 : touch rstn(O) + gpio93 : 5g reset(O) +*/ \ No newline at end of file diff --git a/arch/riscv/boot/dts/eswin/eic7702-evb-a1-d0.dts b/arch/riscv/boot/dts/eswin/eic7702-evb-a1-d0.dts index 1bacf33dd7c0..cbfeadae5c8e 100644 --- a/arch/riscv/boot/dts/eswin/eic7702-evb-a1-d0.dts +++ b/arch/riscv/boot/dts/eswin/eic7702-evb-a1-d0.dts @@ -228,6 +228,7 @@ &pcie { &d0_npu{ status = "okay"; + npu-supply=<&npu_vcc1>; }; &d0_dsp_subsys { @@ -428,7 +429,9 @@ &d0_gmac0 { rst-gpios = <&porta 15 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x290 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; - + dly-param-1000m = <0x23232323 0x800c8023 0x0c0c0c0c>; + dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; + dly-param-10m = <0 0 0>; status = "okay"; }; @@ -438,7 +441,9 @@ &d0_gmac1 { rst-gpios = <&porta 14 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x294 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; - + dly-param-1000m = <0x25252525 0x80268025 0x26262626>; + dly-param-100m = <0x48484848 0x80588048 0x58585858>; + dly-param-10m = <0 0 0>; status = "okay"; }; @@ -624,7 +629,6 @@ npu_vcc1:npu_svcc{ regulator-min-microamp=<20000000>; regulator-max-microamp=<40000000>; regulator-ov-protection-microvolt=<1100000>; - regulator-always-on; }; }; }; diff --git a/arch/riscv/boot/dts/eswin/eic7702-evb-a1-d1.dts b/arch/riscv/boot/dts/eswin/eic7702-evb-a1-d1.dts index 4154b2da9d22..0b2d07df055c 100644 --- a/arch/riscv/boot/dts/eswin/eic7702-evb-a1-d1.dts +++ b/arch/riscv/boot/dts/eswin/eic7702-evb-a1-d1.dts @@ -240,6 +240,7 @@ &pcie { &d0_npu{ status = "okay"; + npu-supply=<&npu_vcc1>; }; &d0_dsp_subsys { @@ -442,7 +443,9 @@ &d0_gmac0 { rst-gpios = <&porta 13 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x290 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; - + dly-param-1000m = <0x23232323 0x800c8023 0x0c0c0c0c>; + dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; + dly-param-10m = <0 0 0>; status = "okay"; }; @@ -452,7 +455,9 @@ &d0_gmac1 { rst-gpios = <&porta 14 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x294 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; - + dly-param-1000m = <0x25252525 0x80268025 0x26262626>; + dly-param-100m = <0x48484848 0x80588048 0x58585858>; + dly-param-10m = <0 0 0>; status = "okay"; }; @@ -638,7 +643,6 @@ npu_vcc1:npu_svcc{ regulator-min-microamp=<20000000>; regulator-max-microamp=<40000000>; regulator-ov-protection-microvolt=<1100000>; - regulator-always-on; }; }; }; diff --git a/arch/riscv/boot/dts/eswin/eic7702-evb-a1-interleave.dts b/arch/riscv/boot/dts/eswin/eic7702-evb-a1-interleave.dts new file mode 100644 index 000000000000..8e38dc5e7f59 --- /dev/null +++ b/arch/riscv/boot/dts/eswin/eic7702-evb-a1-interleave.dts @@ -0,0 +1,1560 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree file for Eswin EIC7700 SoC. + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/dts-v1/; + +#define RTCCLK_FREQ 1000000 +#define LSPCLK_FREQ 200000000 + +/* If wanna enable ECC capability of DDR, should reserve highest zone of 1/8 all space for it */ +#define CMA_SIZE 0x20000000 + +#include "eswin-win2030-die0-soc.dtsi" +#include "eswin-win2030-die1-soc.dtsi" + +#include "eic7x-die0-pinctrl.dtsi" +#include "eic7x-die1-pinctrl.dtsi" +#include +#include +#include + +/* Clock frequency (in Hz) of the PCB crystal for rtcclk */ + +/ { + #address-cells = <2>; + #size-cells = <2>; + model = "ESWIN EIC7700"; + compatible = "sifive,hifive-unmatched-a00", "sifive,fu740-c000", + "sifive,fu740", "eswin,eic7700"; + + aliases { + serial0 = &d0_uart0; + ethernet0 = &d0_gmac0; + ethernet1 = &d0_gmac1; + ethernet2 = &d1_gmac0; + ethernet3 = &d1_gmac1; + rtc0 = &die0_rtc; + rtc1 = &d1_rtc; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + cpus { + timebase-frequency = ; + }; + + memory@59000000 { + device_type = "memory"; + reg = <0x0 0x59000000 0x0 0x400000>; + numa-node-id = <0>; + }; + + memory@79000000 { + device_type = "memory"; + reg = <0x0 0x79000000 0x0 0x400000>; + numa-node-id = <1>; + }; + + memory@4000000000 { + device_type = "memory"; + reg = <0x40 0x00000000 0x0 0x80000000>; + numa-node-id = <0>; + }; + memory@4100000000 { + device_type = "memory"; + reg = <0x41 0x00000000 0x1 0xe0000000>; + numa-node-id = <0>; + }; + memory@42e0000000 { + device_type = "memory"; + reg = <0x42 0xe0000000 0x1 0xe0000000>; + numa-node-id = <1>; + }; + memory@c0000000 { + device_type = "memory"; + reg = <0x00 0xc0000000 0x0 0x40000000>; + numa-node-id = <0>; + }; + memory@2040000000 { + device_type = "memory"; + reg = <0x20 0x40000000 0x0 0x40000000>; + numa-node-id = <1>; + }; + memory@300000000 { + device_type = "memory"; + reg = <0x3 0x0 0x1 0x80000000>; + numa-node-id = <0>; + }; + memory@2280000000 { + device_type = "memory"; + reg = <0x22 0x80000000 0x1 0x80000000>; + numa-node-id = <1>; + }; + memory@2e00000000 { + device_type = "memory"; + reg = <0x2 0xe0000000 0x0 0x20000000>; + numa-node-id = <0>; + }; + memory@2260000000 { + device_type = "memory"; + reg = <0x22 0x60000000 0x0 0x20000000>; + numa-node-id = <1>; + }; + reserved-memory { + #address-cells = <2>; + #size-cells = <2>; + ranges; + linux,cma { + compatible = "shared-dma-pool"; + reusable; + size = <0x0 CMA_SIZE>; + alignment = <0x0 0x1000>; + alloc-ranges = <0x41 0x00000000 0x1 0x0>,<0x43 0x00000000 0x1 0x0>; + linux,cma-default; + }; + mmz_nid_0_part_0 { + compatible = "eswin-reserve-memory"; + reg = <0x3 0x0 0x1 0x80000000>; + no-map; + }; + mmz_nid_1_part_0 { + compatible = "eswin-reserve-memory"; + reg = <0x22 0x80000000 0x1 0x80000000>; + no-map; + }; + npu0_reserved: sprammemory@59000000 { + no-map; + reg = <0x0 0x59000000 0x0 0x400000>; + }; + + npu1_reserved: sprammemory@79000000 { + no-map; + reg = <0x0 0x79000000 0x0 0x400000>; + }; + + d0_dc_reserved: d0_dc_reserved@2e00000000 { + compatible = "shared-dma-pool"; + reusable; + reg = <0x2 0xe0000000 0x0 0x20000000>; + }; + + d1_dc_reserved: d1_dc_reserved@2260000000 { + compatible = "shared-dma-pool"; + reusable; + reg = <0x22 0x60000000 0x0 0x20000000>; + }; + + // g2d_4GB_boundary_reserved_4k { + // no-map; + // reg = <0x0 0xfffff000 0x0 0x1000>; + // }; + + // g2d_8GB_boundary_reserved_4k { + // no-map; + // reg = <0x1 0xfffff000 0x0 0x1000>; + // }; + + // g2d_12GB_boundary_reserved_4k { + // no-map; + // reg = <0x2 0xfffff000 0x0 0x1000>; + // }; + + + // d1_g2d_4GB_boundary_reserved_4k { + // no-map; + // reg = <0x20 0xfffff000 0x0 0x1000>; + // }; + + // d1_g2d_8GB_boundary_reserved_4k { + // no-map; + // reg = <0x21 0xfffff000 0x0 0x1000>; + // }; + + + }; + + distance-map { + compatible = "numa-distance-map-v1"; + distance-matrix = <0 0 10>, + <0 1 100>, + <1 0 100>, + <1 1 10>; + }; + + /* die1 gpio68 system led */ + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_die1_gpio68_default>; + + gpio-68 { + gpios = <&d1_portc 4 GPIO_ACTIVE_LOW>; + label = "heartbeat"; + linux,default-trigger = "heartbeat"; + }; + }; + +}; + +&d0_clock { + status = "okay"; +}; +&d1_clock { + status = "okay"; +}; + +&d0_reset { + status = "okay"; +}; +&d1_reset { + status = "okay"; +}; + +&d0_pmu { + status = "okay"; +}; +&d1_pmu { + status = "disabled"; +}; + +&ddr0 { + status = "okay"; +}; + +&ddr1 { + status = "okay"; +}; + +&d1_ddr0 { + status = "okay"; +}; + +&d1_ddr1 { + status = "okay"; +}; + +&smmu0 { + status = "okay"; +}; +&smmu1 { + status = "okay"; +}; + +&smmu_pmu0 { + status = "disabled"; +}; +&smmu_pmu1 { + status = "disabled"; +}; + + +&dev_foo_a { + status = "okay"; +}; + +&d0_cfg_noc { + status = "okay"; +}; + +&d0_llc_noc { + status = "okay"; + stat,0 = "TracePort:ddr0_p0_req"; + stat,1 = "TracePort:ddr1_p0_req"; + //latency,0 = "TracePort:llcnoc_trans_probe"; + //pending,0 = "TracePort:llcnoc_trans_probe"; +}; + +&d0_sys_noc { + status = "okay"; + + //eswin,DSPT-qos-owner; + //eswin,NPU-qos-owner; + //eswin,SPISLV_TBU3-qos-owner; + + stat,0 = "TracePort:ddr0_p1_req", + "InitFlow:mcput_snoc_mp/I/0"; + + stat,1 = "TracePort:ddr0_p2_req", + "InitFlow:dspt_snoc/I/0", + "AddrBase:0x81000000", "AddrSize:0x30", + "Opcode:RdWrLockUrg", "Status:ReqRsp", "Length:0x8000", "Urgency:0x0"; + + stat,2 = "TracePort:ddr1_p1_req", + "Status:Req", "AddrSize:0x28"; + + stat,3 = "TracePort:ddr1_p2_req"; + + latency,0 = "TracePort:sysnoc_trans_probe_0", "AddrSize:0x0"; + latency,1 = "TracePort:sysnoc_trans_probe_1","Mode:latency","AddrBase:0x82000000","AddrSize:0x28","Opcode:RdWr"; + //latency,2 = "TracePort:sysnoc_trans_probe_2"; + + //pending,0 = "TracePort:sysnoc_trans_probe_0"; + //pending,1 = "TracePort:sysnoc_trans_probe_1","Mode:latency","AddrBase:0x82000000","AddrSize:0x0","Opcode:RdWr"; + pending,0 = "TracePort:sysnoc_trans_probe_2", "AddrSize:0x3"; +}; + +&d0_media_noc { + status = "okay"; + + //eswin,GPU-qos-owner; + //eswin,TBU2-qos-owner; + //eswin,VC-qos-owner; + + stat,0 = "TracePort:ddr0_p3_req"; + stat,1 = "TracePort:ddr1_p3_req"; + //latency,0 = "TracePort:mnoc_trans_probe"; + //pending,0 = "TracePort:mnoc_trans_probe"; +}; + +&d0_realtime_noc { + status = "okay"; + + //eswin,TBU0-qos-owner; + //eswin,VO-qos-owner; + + stat,0 = "TracePort:ddr0_p4_req"; + stat,1 = "TracePort:ddr1_p4_req"; + //latency,0 = "TracePort:rnoc_trans_probe"; + //pending,0 = "TracePort:rnoc_trans_probe"; +}; + +&d0_noc_wdt { + status = "okay"; +}; + +&d1_cfg_noc { + status = "okay"; +}; + +&d1_llc_noc { + status = "okay"; + stat,0 = "TracePort:ddr0_p0_req"; + stat,1 = "TracePort:ddr1_p0_req"; + //latency,0 = "TracePort:llcnoc_trans_probe"; + //pending,0 = "TracePort:llcnoc_trans_probe"; +}; + +&d1_sys_noc { + status = "okay"; + + //eswin,DSPT-qos-owner; + //eswin,NPU-qos-owner; + //eswin,SPISLV_TBU3-qos-owner; + + stat,0 = "TracePort:ddr0_p1_req", + "InitFlow:mcput_snoc_mp/I/0"; + + stat,1 = "TracePort:ddr0_p2_req", + "InitFlow:dspt_snoc/I/0", + "AddrBase:0x81000000", "AddrSize:0x30", + "Opcode:RdWrLockUrg", "Status:ReqRsp", "Length:0x8000", "Urgency:0x0"; + + stat,2 = "TracePort:ddr1_p1_req", + "Status:Req", "AddrSize:0x28"; + + stat,3 = "TracePort:ddr1_p2_req"; + + latency,0 = "TracePort:sysnoc_trans_probe_0", "AddrSize:0x0"; + latency,1 = "TracePort:sysnoc_trans_probe_1","Mode:latency","AddrBase:0x82000000","AddrSize:0x28","Opcode:RdWr"; + //latency,2 = "TracePort:sysnoc_trans_probe_2"; + + //pending,0 = "TracePort:sysnoc_trans_probe_0"; + //pending,1 = "TracePort:sysnoc_trans_probe_1","Mode:latency","AddrBase:0x82000000","AddrSize:0x0","Opcode:RdWr"; + pending,0 = "TracePort:sysnoc_trans_probe_2", "AddrSize:0x3"; +}; + +&d1_media_noc { + status = "okay"; + + //eswin,GPU-qos-owner; + //eswin,TBU2-qos-owner; + //eswin,VC-qos-owner; + + stat,0 = "TracePort:ddr0_p3_req"; + stat,1 = "TracePort:ddr1_p3_req"; + //latency,0 = "TracePort:mnoc_trans_probe"; + //pending,0 = "TracePort:mnoc_trans_probe"; +}; + +&d1_realtime_noc { + status = "okay"; + + //eswin,TBU0-qos-owner; + //eswin,VO-qos-owner; + + stat,0 = "TracePort:ddr0_p4_req"; + stat,1 = "TracePort:ddr1_p4_req"; + //latency,0 = "TracePort:rnoc_trans_probe"; + //pending,0 = "TracePort:rnoc_trans_probe"; +}; + +&d1_noc_wdt { + status = "okay"; +}; + +&d0_ipc_scpu { + status = "okay"; +}; +&d1_ipc_scpu { + status = "okay"; +}; + +&d0_lpcpu { + status = "okay"; +}; +&d1_lpcpu { + status = "disabled"; +}; + +&pcie { + status = "okay"; +}; +&d1_pcie { + status = "okay"; +}; + +&d0_npu{ + status = "okay"; +}; +&d1_npu { + status = "okay"; +}; + +&d0_dsp_subsys { + status = "okay"; +}; +&d1_dsp_subsys { + status = "okay"; +}; + +&d0_dsp0 { + status = "okay"; +}; +&d1_dsp0 { + status = "okay"; +}; + +&d0_dsp1 { + status = "okay"; +}; +&d1_dsp1 { + status = "okay"; +}; + +&d0_dsp2 { + status = "okay"; +}; +&d1_dsp2 { + status = "okay"; +}; + +&d0_dsp3 { + status = "okay"; +}; +&d1_dsp3 { + status = "okay"; +}; + +&gpu0 { + status = "okay"; +}; +&d1_gpu { + status = "disabled"; +}; + +&gc820 { + status = "okay"; +}; +&d1_gc820 { + status = "okay"; +}; + +&vdec0 { + status = "okay"; +}; +&vdec1 { + status = "okay"; +}; + +&venc0 { + status = "okay"; +}; +&venc1 { + status = "okay"; +}; + +&video_output { + status = "okay"; + memory-region = <&d0_dc_reserved>; +}; + +&d1_video_output { + status = "okay"; + memory-region = <&d1_dc_reserved>; +}; + +&dc { + status = "okay"; +}; + +&d1_dc { + status = "okay"; +}; + +&dc_test { + status = "disabled"; +}; +&d1_dc_test { + status = "disabled"; +}; + +&virtual_display { + status = "okay"; +}; + +&d1_virtual_display { + status = "okay"; +}; + +&dsi_controller { + status = "okay"; +}; +&d1_dsi_controller { + status = "okay"; +}; + +&dsi_panel { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_die0_gpio27_default &pinctrl_die0_gpio106_default>; + backlight0-gpios = <&porta 27 GPIO_ACTIVE_HIGH>; + rst-gpios = <&portd 10 GPIO_ACTIVE_HIGH>; +}; +&d1_dsi_panel { + status = "okay"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_die1_gpio69_default &pinctrl_die1_gpio21_default>; + backlight0-gpios = <&d1_portc 5 GPIO_ACTIVE_HIGH>; + rst-gpios = <&d1_porta 21 GPIO_ACTIVE_HIGH>; +}; + +&dw_hdmi { + status = "okay"; + ports { + port@2 { + reg = <2>; + hdmi_in_i2s: endpoint@1 { + system-clock-frequency = <12288000>; + remote-endpoint = <&d0_i2s0_endpoint>; + }; + }; + }; +}; +&d1_dw_hdmi { + status = "okay"; + ports { + port@2 { + reg = <2>; + d1_hdmi_in_i2s: endpoint@1 { + system-clock-frequency = <12288000>; + remote-endpoint = <&d1_i2s0_endpoint>; + }; + }; + }; +}; + +&dw_hdmi_hdcp2 { + status = "okay"; +}; +&d1_dw_hdmi_hdcp2 { + status = "disabled"; +}; + + +&d0_i2s0 { + status = "okay"; + numa-node-id = <0>; + d0_i2s0_port: port { + d0_i2s0_endpoint: endpoint { + remote-endpoint = <&hdmi_in_i2s>; + dai-format = "i2s"; + }; + }; +}; + +&d1_i2s0 { + status = "okay"; + numa-node-id = <1>; + d1_i2s0_port: port { + d1_i2s0_endpoint: endpoint { + remote-endpoint = <&d1_hdmi_in_i2s>; + dai-format = "i2s"; + }; + }; +}; + +&d0_i2s1 { + status = "okay"; + numa-node-id = <0>; + d0_i2s1_port: port { + d0_i2s1_endpoint: endpoint { + remote-endpoint = <&d0_codec0_endpoint>; + dai-format = "i2s"; + }; + }; +}; + +&d1_i2s1 { + status = "okay"; + numa-node-id = <1>; + d1_i2s1_port: port { + d1_i2s1_endpoint: endpoint { + remote-endpoint = <&d1_codec0_endpoint>; + dai-format = "i2s"; + }; + }; +}; + +&d0_i2s2 { + status = "okay"; + numa-node-id = <0>; + d0_i2s2_port: port { + d0_i2s2_endpoint: endpoint { + remote-endpoint = <&d0_codec1_endpoint>; + dai-format = "i2s"; + }; + }; +}; + +&d1_i2s2 { + status = "okay"; + numa-node-id = <1>; + d1_i2s2_port: port { + d1_i2s2_endpoint: endpoint { + remote-endpoint = <&d1_codec1_endpoint>; + dai-format = "i2s"; + }; + }; +}; + +&d0_graphcard0 { + status = "okay"; + label = "Analog Audio-0"; + dais = <&d0_i2s1_port>; +}; + +&d0_graphcard1 { + status = "okay"; + label = "Analog Audio-1"; + dais = <&d0_i2s2_port>; +}; + +&d0_graphcard2 { + status = "okay"; + label = "HDMI Audio-0"; + dais = <&d0_i2s0_port>; +}; + +&d1_graphcard0 { + status = "okay"; + label = "Analog Audio-2"; + dais = <&d1_i2s1_port>; +}; + +&d1_graphcard1 { + status = "okay"; + label = "Analog Audio-3"; + dais = <&d1_i2s2_port>; +}; + +&d1_graphcard2 { + status = "okay"; + label = "HDMI Audio-1"; + dais = <&d1_i2s0_port>; +}; + +&isp_0 { + status = "okay"; +}; +&d1_isp_0 { + status = "disabled"; +}; + +&isp_1 { + status = "okay"; +}; +&d1_isp_1 { + status = "disabled"; +}; + +&dewarp { + status = "okay"; +}; +&d1_dewarp { + status = "okay"; +}; + +&mipi_dphy_rx { + status = "okay"; +}; +&d1_mipi_dphy_rx { + status = "disabled"; +}; + +&csi_dma0 { + status = "okay"; +}; +&d1_csi_dma0 { + status = "disabled"; +}; + +&csi_dma1 { + status = "disabled"; +}; +&d1_csi_dma1 { + status = "disabled"; +}; + +&csi2_0 { + status = "okay"; +}; +&d1_csi2_0 { + status = "disabled"; +}; + +&csi2_1 { + status = "disabled"; +}; +&d1_csi2_1 { + status = "disabled"; +}; + +&sdhci_emmc { + /* emmc */ + status = "okay"; + delay_code = <0x17>; + drive-impedance-ohm = <50>; + enable-cmd-pullup; + enable-data-pullup; + no-sdio; + no-sd; +}; + +&d1_sdhci_emmc { + /* emmc */ + status = "okay"; + delay_code = <0x17>; + drive-impedance-ohm = <50>; + enable-cmd-pullup; + enable-data-pullup; + no-sdio; + no-sd; +}; + +&sdio0 { + /* sd card */ + status = "okay"; + delay_code = <0x55>; + drive-impedance-ohm = <33>; + enable-cmd-pullup; + enable-data-pullup; + no-sdio; + no-mmc; +}; + +&d1_sdio0 { + /* wifi module */ + status = "okay"; + delay_code = <0x29>; + drive-impedance-ohm = <33>; + enable-cmd-pullup; + enable-data-pullup; + keep-power-in-suspend; + non-removable; + no-sd; + no-mmc; + aw315:wifi_aw3155@0 { + compatible = "aml_w1_sdio"; + reg = <0x0>; + interrupt-parent = <&d1_porta>; + interrupts = <18 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default", "default"; + pinctrl-0 = <&pinctrl_die1_gpio18_default>; + pinctrl-1 = <&pinctrl_die1_gpio16_default>; + irq-gpios = <&d1_porta 18 GPIO_ACTIVE_HIGH>; + rst-gpios = <&d1_porta 16 GPIO_ACTIVE_HIGH>; + }; +}; + +&sdio1 { + status = "disabled"; +}; + +&d1_sdio1 { + status = "disabled"; +}; + +&d0_gmac0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_die0_gpio15_default>; + rst-gpios = <&porta 15 GPIO_ACTIVE_LOW>; + eswin,rgmiisel = <&pinctrl 0x290 0x3>; + eswin,led-cfgs = <0x6100 0xa40 0x420>; + dly-param-1000m = <0x23232323 0x800c8023 0x0c0c0c0c>; + dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; + dly-param-10m = <0 0 0>; + status = "okay"; +}; + +&d1_gmac0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_die1_gpio13_default>; + rst-gpios = <&d1_porta 13 GPIO_ACTIVE_LOW>; + eswin,rgmiisel = <&d1_pinctrl 0x290 0x3>; + eswin,led-cfgs = <0x6100 0xa40 0x420>; + dly-param-1000m = <0x23232323 0x800c8023 0x0c0c0c0c>; + dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; + dly-param-10m = <0 0 0>; + status = "okay"; +}; + +&d0_gmac1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_die0_gpio14_default>; + rst-gpios = <&porta 14 GPIO_ACTIVE_LOW>; + eswin,rgmiisel = <&pinctrl 0x294 0x3>; + eswin,led-cfgs = <0x6100 0xa40 0x420>; + dly-param-1000m = <0x25252525 0x80268025 0x26262626>; + dly-param-100m = <0x48484848 0x80588048 0x58585858>; + dly-param-10m = <0 0 0>; + status = "okay"; +}; + +&d1_gmac1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_die1_gpio14_default>; + rst-gpios = <&d1_porta 14 GPIO_ACTIVE_LOW>; + eswin,rgmiisel = <&d1_pinctrl 0x294 0x3>; + eswin,led-cfgs = <0x6100 0xa40 0x420>; + dly-param-1000m = <0x25252525 0x80268025 0x26262626>; + dly-param-100m = <0x48484848 0x80588048 0x58585858>; + dly-param-10m = <0 0 0>; + status = "okay"; +}; + +&d0_sata { + status = "okay"; +}; + +&d1_sata { + status = "okay"; +}; + +&d0_usbdrd3_0 { + status = "okay"; +}; +&d1_usbdrd3_0 { + status = "okay"; +}; + +&d0_usbdrd_dwc3_0 { + status = "okay"; + dr_mode = "host"; + maximum-speed = "super-speed"; +}; + +&d1_usbdrd_dwc3_0 { + status = "okay"; + dr_mode = "host"; + maximum-speed = "super-speed"; +}; + +&d0_usbdrd3_1 { + status = "okay"; +}; + +&d1_usbdrd3_1 { + status = "okay"; +}; + +&d0_usbdrd_dwc3_1 { + status = "okay"; + dr_mode = "host"; + maximum-speed = "super-speed"; +}; + +&d1_usbdrd_dwc3_1 { + status = "okay"; + dr_mode = "host"; + maximum-speed = "super-speed"; +}; + +&d0_dmac0 { + status = "okay"; +}; + +&d1_dmac0 { + status = "disabled"; +}; + +&d0_aon_dmac { + status = "okay"; +}; + +&d1_aon_dmac { + status = "okay"; +}; + +&d0_uart0 { + /* debug */ + status = "okay"; +}; + +&d1_uart0 { + status = "okay"; +}; + +&d0_uart1 { + /* RS232 DB9 */ + status = "okay"; +}; + +&d1_uart1 { + /* BT M.2 KEY-E */ + status = "okay"; +}; + +&d0_uart2 { + /* pin header */ + status = "okay"; +}; + +&d1_uart2 { + /* pin header */ + status = "okay"; +}; + +&d0_uart3 { + /* unused */ + status = "disabled"; +}; + +&d1_uart3 { + /* unused */ + status = "disabled"; +}; + +&d0_uart4 { + /* unused */ + status = "disabled"; +}; + +&d1_uart4 { + /* unused */ + status = "disabled"; +}; + +&ssi0 { + /* spi flash */ + status = "okay"; + num-cs = <2>; + spi-flash@0 { + compatible = "winbond,w25q128fw", + "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <4800000>; + rx-sample-delay-ns = <10>; + }; + spi-flash@1 { + compatible = "winbond,w25q128fw", + "jedec,spi-nor"; + reg = <1>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <4800000>; + rx-sample-delay-ns = <10>; + }; +}; +&d1_ssi0 { + /* spi flash */ + status = "okay"; + num-cs = <2>; + spi-flash@0 { + compatible = "winbond,w25q128fw", + "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <4800000>; + rx-sample-delay-ns = <10>; + }; + spi-flash@1 { + compatible = "winbond,w25q128fw", + "jedec,spi-nor"; + reg = <1>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <4800000>; + rx-sample-delay-ns = <10>; + }; +}; + +&ssi1 { + /* unused */ + status = "disabled"; +}; + +&d1_ssi1 { + /* unused */ + status = "disabled"; +}; + +&bootspi { + /* spi flash */ + status = "disabled"; + num-cs = <1>; + cs-gpios = <&portd 0 GPIO_ACTIVE_LOW>; + wp-gpios = <&portd 4 GPIO_ACTIVE_LOW>; + spi-flash@0 { + compatible = "winbond,w25q128jw", + "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <4800000>; + rx-sample-delay-ns = <10>; + }; +}; + +&d1_bootspi { + /* spi flash */ + status = "disabled"; + num-cs = <1>; + cs-gpios = <&d1_portd 0 GPIO_ACTIVE_LOW>; + wp-gpios = <&d1_portd 4 GPIO_ACTIVE_LOW>; + spi-flash@0 { + compatible = "winbond,w25q128jw", + "jedec,spi-nor"; + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + spi-max-frequency = <4800000>; + rx-sample-delay-ns = <10>; + }; +}; + +&d0_mbox0 { + status = "okay"; +}; +&d1_mbox0 { + status = "okay"; +}; + +&d0_mbox1 { + status = "okay"; +}; +&d1_mbox1 { + status = "okay"; +}; + +&d0_mbox2 { + status = "okay"; +}; +&d1_mbox2 { + status = "okay"; +}; + +&d0_mbox3 { + status = "okay"; +}; +&d1_mbox3 { + status = "okay"; +}; + +&d0_mbox4 { + status = "okay"; +}; +&d1_mbox4 { + status = "okay"; +}; + +&d0_mbox5 { + status = "okay"; +}; +&d1_mbox5 { + status = "okay"; +}; + +&d0_mbox6 { + status = "okay"; +}; +&d1_mbox6 { + status = "okay"; +}; + +&d0_mbox7 { + status = "okay"; +}; +&d1_mbox7 { + status = "okay"; +}; + +&fan_control { + status = "okay"; +}; +&d1_fan_control { + status = "disabled"; +}; + +&d0_i2c0 { + /* codec es8388 */ + status = "okay"; + d0_es8388_0: es8388-0@10 { + compatible = "eswin,es8388"; + reg = <0x10>; + #sound-dai-cells = <0>; + port { + d0_codec0_endpoint: endpoint { + system-clock-frequency = <12288000>; + remote-endpoint = <&d0_i2s1_endpoint>; + }; + }; + }; + d0_es8388_1: es8388-1@11 { + compatible = "eswin,es8388"; + reg = <0x11>; + #sound-dai-cells = <0>; + port { + d0_codec1_endpoint: endpoint { + system-clock-frequency = <12288000>; + remote-endpoint = <&d0_i2s2_endpoint>; + }; + }; + }; +}; + +&d1_i2c0 { + /* codec es8388 */ + status = "okay"; + d1_es8388_0: es8388-0@10 { + compatible = "eswin,es8388"; + reg = <0x10>; + #sound-dai-cells = <0>; + port { + d1_codec0_endpoint: endpoint { + system-clock-frequency = <12288000>; + remote-endpoint = <&d1_i2s1_endpoint>; + }; + }; + }; + d1_es8388_1: es8388-1@11 { + compatible = "eswin,es8388"; + reg = <0x11>; + #sound-dai-cells = <0>; + port { + d1_codec1_endpoint: endpoint { + system-clock-frequency = <12288000>; + remote-endpoint = <&d1_i2s2_endpoint>; + }; + }; + }; +}; + +&d0_i2c1 { + status = "okay"; + es5430@f { + compatible = "einno,es5340"; + reg = <0xf>; + eswin,regulator_default-microvolt=<1000000>; + eswin,regulator_label = "supply vdd1", "npu vdd1", "npu current1", "npu temperature1"; + label = "npu_vdd"; + regulators{ + d0_npu_vcc:npu_svcc{ + regulator-name="NPU_SVCC"; + regulator-min-microvolt=<700000>; + regulator-max-microvolt=<1100000>; + regulator-min-microamp=<20000000>; + regulator-max-microamp=<40000000>; + regulator-ov-protection-microvolt=<1100000>; + regulator-always-on; + }; + }; + }; +}; +&d1_i2c1 { + status = "okay"; + es5430@f { + compatible = "einno,es5340"; + reg = <0xf>; + eswin,regulator_default-microvolt=<1000000>; + eswin,regulator_label = "supply vdd1", "npu vdd1", "npu current1", "npu temperature1"; + label = "d1_npu_vdd"; + regulators{ + d1_npu_vcc:npu_svcc{ + regulator-name="NPU_SVCC2"; + regulator-min-microvolt=<700000>; + regulator-max-microvolt=<1100000>; + regulator-min-microamp=<20000000>; + regulator-max-microamp=<40000000>; + regulator-ov-protection-microvolt=<1100000>; + regulator-always-on; + }; + }; + }; +}; + +&d0_i2c2 { + /* touch screen*/ + status = "okay"; + d0_gt911:touchscreen@14 { + compatible = "goodix,gt911"; + reg = <0x14>; + interrupt-parent = <&porta>; + interrupts = <20 IRQ_TYPE_EDGE_RISING>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_die0_gpio20_default>; + irq-gpios = <&porta 20 GPIO_ACTIVE_HIGH>; + reset-gpios = <&portd 15 GPIO_ACTIVE_HIGH>; + }; +}; + +&d1_i2c2 { + /* touch screen*/ + status = "okay"; + d1_gt911:touchscreen@14 { + compatible = "goodix,gt911"; + reg = <0x14>; + interrupt-parent = <&d1_porta>; + interrupts = <0 IRQ_TYPE_EDGE_RISING>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_die1_gpio0_default>; + irq-gpios = <&d1_porta 0 GPIO_ACTIVE_HIGH>; + reset-gpios = <&d1_portd 15 GPIO_ACTIVE_HIGH>; + }; +}; + +&d0_i2c3 { + /* mipi csi0/csi1 */ + status = "okay"; +}; +&d1_i2c3 { + status = "disabled"; +}; + +&d0_i2c4 { + /* mipi csi2/csi3 */ + status = "disabled"; +}; +&d1_i2c4 { + status = "disabled"; +}; + +&d0_i2c5 { + /* mipi csi4/csi5 */ + status = "disabled"; +}; +&d1_i2c5 { + status = "disabled"; +}; + +&d0_i2c6 { + /* unused */ + status = "disabled"; +}; +&d1_i2c6 { + status = "disabled"; +}; + +&d0_i2c7 { + /* unused */ + status = "disabled"; +}; +&d1_i2c7 { + status = "disabled"; +}; + +&d0_i2c8 { + /* io extended for mipi csi */ + status = "okay"; + tca6416_0: gpio@20 { + compatible = "ti,tca6416"; + reg = <0x20>; + gpio-controller; /* IRQ not connected */ + #gpio-cells = <2>; + gpio-line-names = "MIPI_CSI0_PWDN", "MIPI_CSI0_RESET", "MIPI_CSI1_FBC", "MIPI_CSI1_ENB", + "MIPI_CSI1_RESET", "MIPI_CSI1_PWDN", "FREX_GP0", "", + "MIPI_CSI0_ENB", "MIPI_CSI0_FBC", "FREX_GP2", "MIPI_CSI2_FBC", + "MIPI_CSI2_ENB", "FREX_GP1", "MIPI_CSI2_RESET", "MIPI_CSI2_PWDN"; + }; + tca6416_1: gpio@21 { + compatible = "ti,tca6416"; + reg = <0x21>; + gpio-controller; + #gpio-cells = <2>; + /* IRQ not connected */ + gpio-line-names = "MIPI_CSI3_PWDN", "MIPI_CSI3_RESET", "MIPI_CSI3_ENB", "MIPI_CSI3_FBC", + "MIPI_CSI4_PWDN", "MIPI_CSI4_RESET", "MIPI_CSI4_ENB", "MIPI_CSI4_FBC", + "MIPI_CSI5_FBC", "MIPI_CSI5_ENB", "MIPI_CSI5_RESET", "MIPI_CSI5_PWDN", + "", "", "", ""; + }; +}; +&d1_i2c8 { + status = "disabled"; +}; + +&d0_i2c9 { + /* unused */ + status = "disabled"; +}; +&d1_i2c9 { + status = "disabled"; +}; + +&d0_aon_i2c0 { + /* ina226x3 */ + status = "okay"; + i2c-sda-hold-time-ns = <0x40>; + ina226@40 { + compatible = "ti,ina226"; + #io-channel-cells = <1>; + label = "cpu_vdd"; + reg = <0x40>; + shunt-resistor = <1000>; + }; + ina226@41 { + compatible = "ti,ina226"; + #io-channel-cells = <1>; + label = "d0_lpddr_vdd"; + reg = <0x41>; + shunt-resistor = <1000>; + }; + ina226@44 { + compatible = "ti,ina226"; + #io-channel-cells = <1>; + label = "d0_soc_vdd"; + reg = <0x44>; + shunt-resistor = <1000>; + }; + tmp102@48 { + compatible = "ti,tmp102"; + reg = <0x48>; + label = "d0_board_tmp"; + #thermal-sensor-cells = <1>; + }; +}; + + +&d1_aon_i2c0 { + /* ina226x4 */ + status = "okay"; + i2c-sda-hold-time-ns = <0x40>; + ina226@40 { + compatible = "ti,ina226"; + #io-channel-cells = <1>; + label = "vdd_dc_in"; + reg = <0x40>; + shunt-resistor = <1000>; + }; + ina226@41 { + compatible = "ti,ina226"; + #io-channel-cells = <1>; + label = "d1_lpddr_vdd"; + reg = <0x41>; + shunt-resistor = <1000>; + }; + ina226@44 { + compatible = "ti,ina226"; + #io-channel-cells = <1>; + label = "d1_soc_vdd"; + reg = <0x44>; + shunt-resistor = <1000>; + }; + tmp102@48 { + compatible = "ti,tmp102"; + reg = <0x48>; + label = "d1_board_tmp"; + #thermal-sensor-cells = <1>; + }; +}; +&d1_aon_i2c1 { + status = "disabled"; +}; + +&pwm0 { + /* fan */ + status = "okay"; +}; +&d1_pwm0 { + status = "disabled"; +}; + +&pvt0 { + status = "okay"; +}; +&d1_pvt0 { + status = "okay"; +}; + +&pvt1 { + status = "okay"; +}; +&d1_pvt1 { + status = "okay"; +}; + +&wdt0 { + status = "disabled"; +}; +&d1_wdt0 { + status = "disabled"; +}; + +&wdt1 { + status = "disabled"; +}; +&d1_wdt1 { + status = "disabled"; +}; + +&wdt2 { + status = "disabled"; +}; +&d1_wdt2 { + status = "disabled"; +}; + +&wdt3 { + status = "disabled"; +}; +&d1_wdt3 { + status = "disabled"; +}; + +&die0_rtc { + status = "okay"; +}; +&d1_rtc { + status = "okay"; +}; + +&timer0 { + status = "okay"; +}; +&d1_timer0 { + status = "okay"; +}; + +&timer1 { + status = "okay"; +}; +&d1_timer1 { + status = "okay"; +}; + +&timer2 { + status = "okay"; +}; +&d1_timer2 { + status = "okay"; +}; + +&timer3 { + status = "okay"; +}; +&d1_timer3 { + status = "okay"; +}; + +&pinctrl { + status = "okay"; +}; +&d1_pinctrl { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; +&d1_gpio0 { + status = "okay"; +}; + +&dev_llc_d0{ + /* apply_npu_1G_freq; */ + npu-supply=<&d0_npu_vcc>; + status = "okay"; +}; +&d1_llc_dev{ + /* apply_npu_1G_freq; */ + npu-supply=<&d1_npu_vcc>; + status = "okay"; +}; + +&d2d { + status = "okay"; +}; + +&d1_d2d { + status = "okay"; +}; + +/* die0 GPIO Function Description + + gpio0 : pcie prstn(I) + gpio11 : tmp alert(I) + gpio13 : tf card detect(I) + gpio14 : gphy1 resetn(O) + gpio15 : gphy0 resetn(O) + gpio18 : ina226 alert(I) + gpio20 : lcd touch int(I) + gpio21 : head phone plug/unplug detection2(I) + gpio27 : black light pwr_en(O) + gpio28 : head phone plug/unplug detection1(I) + gpio68 : fan pwm(O) + gpio69 : fan touch(I) + gpio92 : frex gp0(O) + gpio93 : frex gp1(O) + gpio106 : mipi dsi resetn(O) + gpio111 : lcd touch resetn(O) +*/ +/* die1 GPIO Function Description + + gpio0 : lcd touch int(I) + gpio13 : gphy0 resetn(O) + gpio14 : gphy1 resetn(O) + gpio15 : bt wake host(I) + gpio16 : sdio wifi disable(O) + gpio18 : sdio wifi wake host(I) + gpio19 : pcie prstn(I) + gpio20 : head phone plug/unplug detection2(I) + gpio21 : mipi dsi resetn(O) + gpio27 : tmp alert(I) + gpio28 : head phone plug/unplug detection1(I) + gpio68 : system led(O) + gpio69 : black light pwr_en(O) + gpio92 : frex gp0(O) + gpio93 : frex gp1(O) + gpio106 : host wak bt(O) + gpio111 : lcd touch resetn(O) +*/ diff --git a/arch/riscv/boot/dts/eswin/eic7702-evb-a1.dts b/arch/riscv/boot/dts/eswin/eic7702-evb-a1.dts index dfb0f03463bc..2fa3f5441fbb 100644 --- a/arch/riscv/boot/dts/eswin/eic7702-evb-a1.dts +++ b/arch/riscv/boot/dts/eswin/eic7702-evb-a1.dts @@ -373,7 +373,7 @@ &d0_ipc_scpu { status = "okay"; }; &d1_ipc_scpu { - status = "disabled"; + status = "okay"; }; &d0_lpcpu { @@ -775,7 +775,9 @@ &d0_gmac0 { rst-gpios = <&porta 15 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x290 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; - + dly-param-1000m = <0x23232323 0x800c8023 0x0c0c0c0c>; + dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; + dly-param-10m = <0 0 0>; status = "okay"; }; @@ -785,7 +787,9 @@ &d1_gmac0 { rst-gpios = <&d1_porta 13 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&d1_pinctrl 0x290 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; - + dly-param-1000m = <0x23232323 0x800c8023 0x0c0c0c0c>; + dly-param-100m = <0x50505050 0x803f8050 0x3f3f3f3f>; + dly-param-10m = <0 0 0>; status = "okay"; }; @@ -795,7 +799,9 @@ &d0_gmac1 { rst-gpios = <&porta 14 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&pinctrl 0x294 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; - + dly-param-1000m = <0x25252525 0x80268025 0x26262626>; + dly-param-100m = <0x48484848 0x80588048 0x58585858>; + dly-param-10m = <0 0 0>; status = "okay"; }; @@ -805,7 +811,9 @@ &d1_gmac1 { rst-gpios = <&d1_porta 14 GPIO_ACTIVE_LOW>; eswin,rgmiisel = <&d1_pinctrl 0x294 0x3>; eswin,led-cfgs = <0x6100 0xa40 0x420>; - + dly-param-1000m = <0x25252525 0x80268025 0x26262626>; + dly-param-100m = <0x48484848 0x80588048 0x58585858>; + dly-param-10m = <0 0 0>; status = "okay"; }; diff --git a/arch/riscv/boot/dts/eswin/eic770x-ooptable.dtsi b/arch/riscv/boot/dts/eswin/eic770x-ooptable.dtsi new file mode 100644 index 000000000000..471984153c44 --- /dev/null +++ b/arch/riscv/boot/dts/eswin/eic770x-ooptable.dtsi @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Device Tree Include file for pin control of Eswin EIC770x family SoC. + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +/ { + cpu_opp_table: opp-table@cpu { + compatible = "operating-points-v2"; + opp-shared; + + opp-24000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-100000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-200000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-400000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-500000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-600000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-700000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-800000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-900000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-1000000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-1200000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-1300000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + opp-1400000000 { + opp-hz = /bits/ 64 ; + opp-microvolt = <800000>; + clock-latency-ns = <70000>; + }; + }; + + dsp_opp_table: opp-table@dsp { + compatible = "operating-points-v2"; + opp@520000000 { + opp-hz = /bits/ 64 <520000000>; + opp-microvolt = <800000>; + }; + opp@1040000000 { + opp-hz = /bits/ 64 <1040000000>; + opp-microvolt = <800000>; + }; + }; + npu_opp_table: opp-table@npu { + compatible = "operating-points-v2"; + opp@1040000000 { + opp-hz = /bits/ 64 <1040000000>; + opp-microvolt = <900000>; + }; + opp@1500000000 { + opp-hz = /bits/ 64 <1500000000>; + opp-microvolt = <1050000>; + }; + + }; + + g2d_opp_table: opp-table@g2d { + compatible = "operating-points-v2"; + opp@260000000 { + opp-hz = /bits/ 64 <260000000>; + opp-microvolt = <800000>; + }; + opp@520000000 { + opp-hz = /bits/ 64 <520000000>; + opp-microvolt = <800000>; + }; + opp@693333334 { + opp-hz = /bits/ 64 <693333334>; + opp-microvolt = <800000>; + }; + opp@1040000000 { + opp-hz = /bits/ 64 <1040000000>; + opp-microvolt = <800000>; + }; + }; + + vi_opp_table: opp-table@vi { + compatible = "operating-points-v2"; + opp@800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <800000>; + }; + opp@400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <800000>; + }; + opp@200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <800000>; + }; + }; + + venc_opp_table: opp-table@venc { + compatible = "operating-points-v2"; + opp@800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <800000>; + }; + opp@400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <800000>; + }; + opp@200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <800000>; + }; + }; + + vdec_opp_table: opp-table@vdec { + compatible = "operating-points-v2"; + opp@800000000 { + opp-hz = /bits/ 64 <800000000>; + opp-microvolt = <800000>; + }; + opp@400000000 { + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <800000>; + }; + opp@200000000 { + opp-hz = /bits/ 64 <200000000>; + opp-microvolt = <800000>; + }; + }; +}; diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-arch-d2d.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-arch-d2d.dtsi index c9afd60d2434..5847de53a516 100644 --- a/arch/riscv/boot/dts/eswin/eswin-win2030-arch-d2d.dtsi +++ b/arch/riscv/boot/dts/eswin/eswin-win2030-arch-d2d.dtsi @@ -20,6 +20,7 @@ #define CHIPLET_AND_DIE (0x2) #include "eswin-win2030-arch.dtsi" +#include "eic770x-ooptable.dtsi" &L64 { @@ -105,7 +106,7 @@ cpu_4: cpu@4 { tlb-split; numa-node-id = <1>; clocks = <&d1_clock WIN2030_CLK_CPU_EXT_SRC_CORE_CLK_0>; - operating-points-v2 = <&d1_cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; cpu-idle-states = <&CPU_RET>; cpu4_intc: interrupt-controller { #interrupt-cells = <1>; @@ -153,7 +154,7 @@ cpu_5: cpu@5 { tlb-split; numa-node-id = <1>; clocks = <&d1_clock WIN2030_CLK_CPU_EXT_SRC_CORE_CLK_1>; - operating-points-v2 = <&d1_cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; cpu-idle-states = <&CPU_RET>; cpu5_intc: interrupt-controller { #interrupt-cells = <1>; @@ -200,7 +201,7 @@ cpu_6: cpu@6 { tlb-split; numa-node-id = <1>; clocks = <&d1_clock WIN2030_CLK_CPU_EXT_SRC_CORE_CLK_2>; - operating-points-v2 = <&d1_cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; cpu-idle-states = <&CPU_RET>; cpu6_intc: interrupt-controller { #interrupt-cells = <1>; @@ -247,7 +248,7 @@ cpu_7: cpu@7 { tlb-split; numa-node-id = <1>; clocks = <&d1_clock WIN2030_CLK_CPU_EXT_SRC_CORE_CLK_3>; - operating-points-v2 = <&d1_cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; cpu-idle-states = <&CPU_RET>; cpu7_intc: interrupt-controller { #interrupt-cells = <1>; @@ -272,6 +273,7 @@ PMU1: pmu@1 { riscv,event-to-mhpmevent = <0x4 0x0 0x202 0x5 0x0 0x4000 0x6 0x0 0x2001 0x10009 0x0 0x102 0x10019 0x0 0x1002 0x10021 0x0 0x802>; compatible = "riscv,pmu0", "riscv,pmu"; interrupts-extended = <&cpu4_intc 13 &cpu5_intc 13 &cpu6_intc 13 &cpu7_intc 13>; + numa-node-id = <1>; }; d1_bus_err0: bus-error-unit@21700000 { @@ -280,6 +282,7 @@ d1_bus_err0: bus-error-unit@21700000 { interrupts = <517>; reg = <0x0 0x21700000 0x0 0x1000>; reg-names = "control"; + numa-node-id = <1>; }; d1_bus_err1: bus-error-unit@21701000 { compatible = "sifive,buserror"; @@ -287,6 +290,7 @@ d1_bus_err1: bus-error-unit@21701000 { interrupts = <518>; reg = <0x0 0x21701000 0x0 0x1000>; reg-names = "control"; + numa-node-id = <1>; }; d1_bus_err2: bus-error-unit@21702000 { compatible = "sifive,buserror"; @@ -294,6 +298,7 @@ d1_bus_err2: bus-error-unit@21702000 { interrupts = <519>; reg = <0x0 0x21702000 0x0 0x1000>; reg-names = "control"; + numa-node-id = <1>; }; d1_bus_err3: bus-error-unit@21703000 { compatible = "sifive,buserror"; @@ -301,6 +306,7 @@ d1_bus_err3: bus-error-unit@21703000 { interrupts = <520>; reg = <0x0 0x21703000 0x0 0x1000>; reg-names = "control"; + numa-node-id = <1>; }; D1CACHE: cache-controller@22010000 { @@ -356,6 +362,7 @@ d1_l2_cache_0: pl2@20104000 { reg-names = "control"; sifive,ecc-granularity = <16>; sifive,perfmon-counters = <6>; + numa-node-id = <1>; }; d1_l2_cache_1: pl2@20108000 { cache-block-size = <64>; @@ -369,6 +376,7 @@ d1_l2_cache_1: pl2@20108000 { reg-names = "control"; sifive,ecc-granularity = <16>; sifive,perfmon-counters = <6>; + numa-node-id = <1>; }; d1_l2_cache_2: pl2@2010c000 { cache-block-size = <64>; @@ -382,6 +390,7 @@ d1_l2_cache_2: pl2@2010c000 { reg-names = "control"; sifive,ecc-granularity = <16>; sifive,perfmon-counters = <6>; + numa-node-id = <1>; }; d1_l2_cache_3: pl2@20110000 { cache-block-size = <64>; @@ -395,6 +404,7 @@ d1_l2_cache_3: pl2@20110000 { reg-names = "control"; sifive,ecc-granularity = <16>; sifive,perfmon-counters = <6>; + numa-node-id = <1>; }; }; diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-arch.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-arch.dtsi index 64671ff693e3..1bcfba13d1a3 100644 --- a/arch/riscv/boot/dts/eswin/eswin-win2030-arch.dtsi +++ b/arch/riscv/boot/dts/eswin/eswin-win2030-arch.dtsi @@ -19,6 +19,7 @@ */ #include +#include "eic770x-ooptable.dtsi" #define UART0_INT 100 #define UART1_INT 101 @@ -84,7 +85,7 @@ cpu_0: cpu@0 { tlb-split; numa-node-id = <0>; clocks = <&d0_clock WIN2030_CLK_CPU_EXT_SRC_CORE_CLK_0>; - operating-points-v2 = <&d0_cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; dynamic-power-coefficient = <324>; cpu-idle-states = <&CPU_RET>; @@ -130,7 +131,7 @@ cpu_1: cpu@1 { tlb-split; numa-node-id = <0>; clocks = <&d0_clock WIN2030_CLK_CPU_EXT_SRC_CORE_CLK_1>; - operating-points-v2 = <&d0_cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; dynamic-power-coefficient = <324>; cpu-idle-states = <&CPU_RET>; @@ -176,7 +177,7 @@ cpu_2: cpu@2 { tlb-split; numa-node-id = <0>; clocks = <&d0_clock WIN2030_CLK_CPU_EXT_SRC_CORE_CLK_2>; - operating-points-v2 = <&d0_cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; dynamic-power-coefficient = <324>; cpu-idle-states = <&CPU_RET>; @@ -222,7 +223,7 @@ cpu_3: cpu@3 { tlb-split; numa-node-id = <0>; clocks = <&d0_clock WIN2030_CLK_CPU_EXT_SRC_CORE_CLK_3>; - operating-points-v2 = <&d0_cpu_opp_table>; + operating-points-v2 = <&cpu_opp_table>; #cooling-cells = <2>; dynamic-power-coefficient = <324>; cpu-idle-states = <&CPU_RET>; @@ -233,12 +234,7 @@ cpu3_intc: interrupt-controller { }; }; }; - L50: memory@80000000 { - compatible = "sifive,axi4-mem-port", "sifive,axi4-port", "sifive,mem-port"; - device_type = "memory"; - reg = <0x0 0x80000000 0x7f 0x80000000>; - sifive,port-width-bytes = <32>; - }; + SOC: soc { #address-cells = <2>; #size-cells = <2>; @@ -252,6 +248,7 @@ PMU0: pmu@0 { riscv,event-to-mhpmevent = <0x4 0x0 0x202 0x5 0x0 0x4000 0x6 0x0 0x2001 0x10009 0x0 0x102 0x10019 0x0 0x1002 0x10021 0x0 0x802>; compatible = "riscv,pmu0", "riscv,pmu"; interrupts-extended = <&cpu0_intc 13 &cpu1_intc 13 &cpu2_intc 13 &cpu3_intc 13>; + numa-node-id = <0>; }; L40: authentication-controller { compatible = "sifive,authentication0"; @@ -297,6 +294,7 @@ d0_bus_err0: bus-error-unit@hart0 { interrupts = <517>; reg = <0x0 0x1700000 0x0 0x1000>; reg-names = "control"; + numa-node-id = <0>; }; d0_bus_err1: bus-error-unit@hart1 { compatible = "sifive,buserror"; @@ -304,6 +302,7 @@ d0_bus_err1: bus-error-unit@hart1 { interrupts = <518>; reg = <0x0 0x1701000 0x0 0x1000>; reg-names = "control"; + numa-node-id = <0>; }; d0_bus_err2: bus-error-unit@hart2 { compatible = "sifive,buserror"; @@ -311,6 +310,7 @@ d0_bus_err2: bus-error-unit@hart2 { interrupts = <519>; reg = <0x0 0x1702000 0x0 0x1000>; reg-names = "control"; + numa-node-id = <0>; }; d0_bus_err3: bus-error-unit@hart3 { compatible = "sifive,buserror"; @@ -318,6 +318,7 @@ d0_bus_err3: bus-error-unit@hart3 { interrupts = <520>; reg = <0x0 0x1703000 0x0 0x1000>; reg-names = "control"; + numa-node-id = <0>; }; D0CACHE: cache-controller@2010000 { cache-block-size = <64>; @@ -328,7 +329,7 @@ D0CACHE: cache-controller@2010000 { compatible = "sifive,ccache1", "cache", "sifive,fu740-c000-ccache"; interrupt-parent = <&plic0>; interrupts = <1>, <3>, <4>, <2>; - next-level-cache = <&L9 &L10 &L11 &L50>; + next-level-cache = <&L9 &L10 &L11>; reg = <0x0 0x2010000 0x0 0x4000 0x0 0x8000000 0x0 0x400000>; reg-names = "control", "sideband"; sifive,a-mshr-count = <60>; @@ -386,6 +387,7 @@ d0_l2_cache_0: pl2@104000 { reg-names = "control"; sifive,ecc-granularity = <16>; sifive,perfmon-counters = <6>; + numa-node-id = <0>; }; d0_l2_cache_1: pl2@108000 { cache-block-size = <64>; @@ -399,6 +401,7 @@ d0_l2_cache_1: pl2@108000 { reg-names = "control"; sifive,ecc-granularity = <16>; sifive,perfmon-counters = <6>; + numa-node-id = <0>; }; d0_l2_cache_2: pl2@10c000 { cache-block-size = <64>; @@ -412,6 +415,7 @@ d0_l2_cache_2: pl2@10c000 { reg-names = "control"; sifive,ecc-granularity = <16>; sifive,perfmon-counters = <6>; + numa-node-id = <0>; }; d0_l2_cache_3: pl2@110000 { cache-block-size = <64>; @@ -425,6 +429,7 @@ d0_l2_cache_3: pl2@110000 { reg-names = "control"; sifive,ecc-granularity = <16>; sifive,perfmon-counters = <6>; + numa-node-id = <0>; }; L10: rom@1a000000 { compatible = "ucbbar,cacheable-zero0"; diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-noc.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-noc.dtsi index fe81f8e622e6..77243ae1b93f 100644 --- a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-noc.dtsi +++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-noc.dtsi @@ -24,6 +24,7 @@ d0_cfg_noc:d0_cfg_noc{ #size-cells = <2>; ranges; reg = <0 0x52060000 0 0x4000>; + numa-node-id = <0>; interrupts = <446>; interrupt-names = "error"; @@ -273,6 +274,7 @@ d0_llc_noc:d0_llc_noc@52081400 { #address-cells = <2>; #size-cells = <2>; ranges; + numa-node-id = <0>; reg = <0 0x52081400 0 0x4000>; interrupts = <441>; interrupt-names = "error"; @@ -548,6 +550,7 @@ d0_sys_noc:d0_sys_noc@52002C00 { #address-cells = <2>; #size-cells = <2>; ranges; + numa-node-id = <0>; reg = <0 0x52002C00 0 0x4000>; interrupts = <431>; interrupt-names = "error"; @@ -2220,6 +2223,7 @@ d0_media_noc:d0_media_noc@52021400 { #address-cells = <2>; #size-cells = <2>; ranges; + numa-node-id = <0>; reg = <0 0x52021400 0 0x4000>; interrupts = <454>; interrupt-names = "error"; @@ -2530,6 +2534,7 @@ d0_realtime_noc:d0_realtime_noc@52041400 { #address-cells = <2>; #size-cells = <2>; ranges; + numa-node-id = <0>; reg = <0 0x52041400 0 0x4000>; interrupts = <448>; interrupt-names = "error"; diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi index 7df6029a9451..8858283c1e68 100644 --- a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi +++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi @@ -32,77 +32,6 @@ / { compatible = "sifive,hifive-unmatched-a00", "sifive,fu740-c000","sifive,fu740"; - d0_cpu_opp_table: opp-table0 { - compatible = "operating-points-v2"; - opp-shared; - - opp-24000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-100000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-200000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-400000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-500000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-600000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-700000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-800000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-900000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-1000000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-1200000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-1300000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-1400000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - }; - thermal-zones { thermal0 { polling-delay-passive = <500>; /*ms*/ @@ -111,9 +40,10 @@ thermal0 { thermal-sensors = <&pvt0>; trips { + /* threshold: trip-point0 { - temperature = <60000>; /* DC*1000 */ - hysteresis = <1000>; /* DC*1000 */ + temperature = <60000>; + hysteresis = <1000>; type = "passive"; }; target: trip-point1 { @@ -121,14 +51,16 @@ target: trip-point1 { hysteresis = <1000>; type = "passive"; }; + */ crit: trip-point2 { - temperature = <110000>; + temperature = <88000>; hysteresis = <0>; type = "critical"; }; }; cooling-maps { + /* map0 { trip = <&target>; contribution = <1024>; @@ -140,14 +72,15 @@ map0 { }; map1 { trip = <&target>; - contribution = <1024>; /*TBD*/ + contribution = <1024>; cooling-device = <&d0_npu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map2 { trip = <&target>; - contribution = <1024>; /*TBD*/ + contribution = <1024>; cooling-device = <&gpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; + */ }; }; }; @@ -241,10 +174,12 @@ d0_sys_crg: sys-crg@51828000 { d0_reset: reset-controller { compatible = "eswin,win2030-reset"; #reset-cells = <2>; + numa-node-id = <0>; }; d0_clock: clock-controller { compatible = "eswin,win2030-clock"; #clock-cells = <1>; + numa-node-id = <0>; }; }; @@ -253,10 +188,12 @@ hfclk: hfclk { compatible = "fixed-clock"; clock-frequency = ; clock-output-names = "hfclk"; + numa-node-id = <0>; }; d0_hsp_sp_csr: hsp_sp_top_csr@0x50440000 { compatible = "eswin,win2030-hsp-sp-csr", "syscon"; + numa-node-id = <0>; #size-cells = <2>; reg = <0x0 0x50440000 0x0 0x2000>; }; @@ -482,11 +419,12 @@ d0_gmac0: ethernet@50400000 { clock-names = "app", "stmmaceth","tx"; resets = <&d0_reset HSPDMA_RST_CTRL SW_HSP_ETH0_ARSTN>; reset-names = "ethrst"; - iommus = <&smmu0 WIN2030_SID_ETH0>; + //iommus = <&smmu0 WIN2030_SID_ETH0>; tbus = ; dma-noncoherent; eswin,hsp_sp_csr = <&d0_hsp_sp_csr 0x1030 0x100 0x108>; eswin,syscrg_csr = <&d0_sys_crg 0x148 0x14c>; + eswin,dly_hsp_reg = <0x114 0x118 0x11c>; snps,axi-config = <&d0_stmmac_axi_setup>; d0_stmmac_axi_setup: stmmac-axi-config { snps,blen = <0 0 0 0 16 8 4>; @@ -512,11 +450,12 @@ d0_gmac1: ethernet@50410000 { clock-names = "app", "stmmaceth","tx"; resets = <&d0_reset HSPDMA_RST_CTRL SW_HSP_ETH1_ARSTN>; reset-names = "ethrst"; - iommus = <&smmu0 WIN2030_SID_ETH1>; + //iommus = <&smmu0 WIN2030_SID_ETH1>; tbus = ; dma-noncoherent; eswin,hsp_sp_csr = <&d0_hsp_sp_csr 0x1034 0x200 0x208>; eswin,syscrg_csr = <&d0_sys_crg 0x148 0x14c>; + eswin,dly_hsp_reg = <0x214 0x218 0x21c>; snps,axi-config = <&d0_stmmac_axi_setup_gmac1>; d0_stmmac_axi_setup_gmac1: stmmac-axi-config { snps,blen = <0 0 0 0 16 8 4>; @@ -530,6 +469,7 @@ noc { #address-cells = <2>; #size-cells = <2>; ranges; + numa-node-id = <0>; #include "eswin-win2030-die0-noc.dtsi" }; @@ -549,11 +489,17 @@ d0_npu: eswin-npu@51c00000 { clocks = <&d0_clock WIN2030_CLK_NPU_ACLK>, <&d0_clock WIN2030_CLK_NPU_CFG_CLK>, <&d0_clock WIN2030_CLK_NPU_CLK>, - <&d0_clock WIN2030_CLK_NPU_E31_CLK>; - clock-names = "aclk", "cfg_clk", "core_clk", "e31_core_clk"; + <&d0_clock WIN2030_CLK_NPU_E31_CLK>, + <&d0_clock WIN2030_MUX_U_NPU_CORE_3MUX1_GFREE>, + <&d0_clock WIN2030_SPLL2_FOUT2>, + <&d0_clock WIN2030_SPLL1_FOUT1>; + + clock-names = "aclk", "cfg_clk", "core_clk", "e31_core_clk", "mux_u_npu_core_3mux1_gfree", "fixed_rate_clk_spll2_fout2", + "fixed_rate_clk_spll1_fout1"; resets = <&d0_reset NPU_RST_CTRL SW_NPU_E31CORE_RSTN>; reset-names = "e31_core"; + operating-points-v2 = <&npu_opp_table>; numa-node-id = <0>; firmware-name = "eic7700_die0_e31_fw"; @@ -593,6 +539,7 @@ d0_dsp_subsys:dsp_subsys@52280400 { reg = <0x0 0x52280400 0x0 0x10000>, <0x0 0x51810000 0x0 0x8000>; ranges; + numa-node-id = <0>; dma-ranges = <0x0 0x30000000 0x0 0xc0000000 0x0 0xce000000>; compatible = "es-dsp-subsys", "simple-bus"; clocks = <&d0_clock WIN2030_CLK_DSPT_CFG_CLK>, <&d0_clock WIN2030_CLK_DSPT_ACLK>; @@ -614,6 +561,7 @@ d0_dsp0:es_dsp@0 { 0x28120000 0 0x5b120000 0x20000>; clocks = <&d0_clock WIN2030_CLK_DSP_ACLK_0>; clock-names = "aclk"; + operating-points-v2 = <&dsp_opp_table>; dsp_mbox = <&d0_mbox4>; device-irq = <11 ESWIN_MAILBOX_DSP_0_TO_U84_REG_BASE @@ -644,6 +592,7 @@ d0_dsp1:es_dsp@1 { 0x28120000 0 0x5b160000 0x20000>; clocks = <&d0_clock WIN2030_CLK_DSP_ACLK_1>; clock-names = "aclk"; + operating-points-v2 = <&dsp_opp_table>; dsp_mbox = <&d0_mbox5>; device-irq = <13 ESWIN_MAILBOX_DSP_1_TO_U84_REG_BASE @@ -673,6 +622,7 @@ d0_dsp2:es_dsp@2 { 0x28120000 0 0x5b1a0000 0x20000>; clocks = <&d0_clock WIN2030_CLK_DSP_ACLK_2>; clock-names = "aclk"; + operating-points-v2 = <&dsp_opp_table>; dsp_mbox = <&d0_mbox6>; device-irq = <15 ESWIN_MAILBOX_DSP_2_TO_U84_REG_BASE @@ -702,6 +652,7 @@ d0_dsp3:es_dsp@3 { 0x28120000 0 0x5b1e0000 0x20000>; clocks = <&d0_clock WIN2030_CLK_DSP_ACLK_3>; clock-names = "aclk"; + operating-points-v2 = <&dsp_opp_table>; dsp_mbox = <&d0_mbox7>; device-irq = <17 ESWIN_MAILBOX_DSP_3_TO_U84_REG_BASE @@ -722,6 +673,27 @@ ESWIN_MAIBOX_U84_IRQ_BIT dsp@0 { }; }; + d0_sofdsp3: sofdsp@4 { + #sound-dai-cells = <1>; + #address-cells = <2>; + #size-cells = <2>; + compatible = "eswin,sof-dsp"; + reg = <0x0 0x5b018000 0x0 0x8000>, + <0x0 0x5b1c0000 0x0 0x40000>; + mbox-names = "dsp-mbox"; + mboxes = <&d0_mbox7 0>; + clocks = <&d0_clock WIN2030_CLK_DSP_ACLK_3>; + clock-names = "aclk"; + process-id = <3>; + iommus = <&smmu0 WIN2030_SID_DSP_3>; + tbus = ; + dma-noncoherent; + mailbox-dsp-to-u84-addr = ; + mailbox-u84-to-dsp-addr = ; + dsp-uart = <&d0_uart0>; + device-uart-mutex = <0x51820000>; + numa-node-id = <0>; + }; }; gc820: g2d@50140000 { @@ -751,6 +723,7 @@ gc820: g2d@50140000 { contiguous-size = <0xa00000>; recovery = <0>; dma-noncoherent; + operating-points-v2 = <&g2d_opp_table>; numa-node-id = <0>; }; @@ -772,6 +745,7 @@ gpu0: gpu@51400000 { interrupt-parent = <&plic0>; interrupts = <15>; dma-noncoherent; + numa-node-id = <0>; #cooling-cells = <2>; dynamic-power-coefficient = <0>; /*TBD*/ @@ -893,6 +867,7 @@ bootspi: spi@51800000 { reset-names = "rst"; spi-max-frequency = <4800000>; reg-io-width = <4>; + numa-node-id = <0>; status = "disabled"; }; sdhci_emmc: mmc@50450000 { @@ -1024,6 +999,7 @@ vdec0: video-decoder0@50100000 { <&d0_reset VD_RST_CTRL SW_VD_AXI_RSTN>; reset-names = "axi", "cfg", "moncfg", "jd_cfg", "jd_axi", "vd_cfg", "vd_axi"; eswin,syscfg = <&d0_sys_con 0x0 0x4>; + operating-points-v2 = <&vdec_opp_table>; vcmd-core = <0 0x6c>; axife-core = <0x200 0x100>; @@ -1072,6 +1048,7 @@ venc0: video-encoder@50110000 { <&d0_reset VE_RST_CTRL SW_VE_AXI_RSTN>; reset-names = "axi", "cfg", "moncfg", "je_cfg", "je_axi", "ve_cfg", "ve_axi"; eswin,syscfg = <&d0_sys_con 0x0 0x4>; + operating-points-v2 = <&venc_opp_table>; vcmd-core = <0 0x6c>; axife-core = <0x2000 0x7d0>; @@ -1115,6 +1092,7 @@ d0_mbox0: mbox@50a00000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + numa-node-id = <0>; dma-noncoherent; }; @@ -1134,6 +1112,7 @@ d0_mbox1: mbox@50a20000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + numa-node-id = <0>; dma-noncoherent; }; @@ -1153,6 +1132,7 @@ d0_mbox2: mbox@50a40000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + numa-node-id = <0>; dma-noncoherent; }; @@ -1172,6 +1152,7 @@ d0_mbox3: mbox@50a60000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + numa-node-id = <0>; dma-noncoherent; }; @@ -1191,6 +1172,7 @@ d0_mbox4: mbox@50a80000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + numa-node-id = <0>; dma-noncoherent; }; @@ -1210,6 +1192,7 @@ d0_mbox5: mbox@50aa0000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + numa-node-id = <0>; dma-noncoherent; }; @@ -1229,6 +1212,7 @@ d0_mbox6: mbox@50ac0000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + numa-node-id = <0>; dma-noncoherent; }; @@ -1248,6 +1232,7 @@ d0_mbox7: mbox@50ae0000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + numa-node-id = <0>; dma-noncoherent; }; @@ -1303,6 +1288,7 @@ pvt0: pvt@0x50b00000 { #thermal-sensor-cells = <0>; status = "disabled"; label = "pvt0"; + numa-node-id = <0>; }; pvt1: pvt@0x52360000 { compatible = "eswin,eswin-pvt-ddr"; @@ -1317,6 +1303,7 @@ pvt1: pvt@0x52360000 { interrupt-parent = <&plic0>; status = "disabled"; label = "pvt1"; + numa-node-id = <0>; }; fan_control: fan_control@50b50000 { @@ -1333,9 +1320,10 @@ fan_control: fan_control@50b50000 { pwm-minimum-period = <1000>; pwms = <&pwm0 0 100000>; pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_die0_fan_tach_default>; + pinctrl-0 = <&pinctrl_die0_fan_tach_default &pinctrl_die0_pwm0_default>; status = "disabled"; label = "fan_control"; + numa-node-id = <0>; }; d0_i2c0: i2c@50950000 { @@ -1350,6 +1338,7 @@ d0_i2c0: i2c@50950000 { reg = <0x0 0x50950000 0x0 0x8000>; interrupts = <105>; interrupt-parent = <&plic0>; + numa-node-id = <0>; }; d0_i2c1: i2c@50960000 { compatible = "snps,designware-i2c"; @@ -1363,6 +1352,7 @@ d0_i2c1: i2c@50960000 { reg = <0x0 0x50960000 0x0 0x10000>; interrupts = <106>; interrupt-parent = <&plic0>; + numa-node-id = <0>; }; d0_i2c2: i2c@50970000 { compatible = "snps,designware-i2c"; @@ -1376,6 +1366,7 @@ d0_i2c2: i2c@50970000 { reg = <0x0 0x50970000 0x0 0x8000>; interrupts = <107>; interrupt-parent = <&plic0>; + numa-node-id = <0>; }; d0_i2c3: i2c@50980000 { compatible = "snps,designware-i2c"; @@ -1389,6 +1380,7 @@ d0_i2c3: i2c@50980000 { reg = <0x0 0x50980000 0x0 0x8000>; interrupts = <108>; interrupt-parent = <&plic0>; + numa-node-id = <0>; }; d0_i2c4: i2c@50990000 { compatible = "snps,designware-i2c"; @@ -1402,6 +1394,7 @@ d0_i2c4: i2c@50990000 { reg = <0x0 0x50990000 0x0 0x8000>; interrupts = <109>; interrupt-parent = <&plic0>; + numa-node-id = <0>; }; d0_i2c5: i2c@509a0000 { compatible = "snps,designware-i2c"; @@ -1415,6 +1408,7 @@ d0_i2c5: i2c@509a0000 { reg = <0x0 0x509a0000 0x0 0x8000>; interrupts = <110>; interrupt-parent = <&plic0>; + numa-node-id = <0>; }; d0_i2c6: i2c@509b0000 { compatible = "snps,designware-i2c"; @@ -1428,6 +1422,7 @@ d0_i2c6: i2c@509b0000 { reg = <0x0 0x509b0000 0x0 0x8000>; interrupts = <111>; interrupt-parent = <&plic0>; + numa-node-id = <0>; }; d0_i2c7: i2c@509c0000 { compatible = "snps,designware-i2c"; @@ -1441,6 +1436,7 @@ d0_i2c7: i2c@509c0000 { reg = <0x0 0x509c0000 0x0 0x8000>; interrupts = <112>; interrupt-parent = <&plic0>; + numa-node-id = <0>; }; d0_i2c8: i2c@509d0000 { compatible = "snps,designware-i2c"; @@ -1454,6 +1450,7 @@ d0_i2c8: i2c@509d0000 { reg = <0x0 0x509d0000 0x0 0x8000>; interrupts = <113>; interrupt-parent = <&plic0>; + numa-node-id = <0>; }; d0_i2c9: i2c@509e0000 { compatible = "snps,designware-i2c"; @@ -1467,6 +1464,7 @@ d0_i2c9: i2c@509e0000 { reg = <0x0 0x509e0000 0x0 0x8000>; interrupts = <114>; interrupt-parent = <&plic0>; + numa-node-id = <0>; }; d0_aon_i2c0: i2c@51830000 { compatible = "snps,designware-i2c"; @@ -1489,6 +1487,7 @@ d0_aon_i2c0: i2c@51830000 { * 0xff : no need to select to dma controller */ dmas = <&d0_aon_dmac 41 0xff>, <&d0_aon_dmac 42 0xff>; + numa-node-id = <0>; }; d0_aon_i2c1: i2c@51838000 { compatible = "snps,designware-i2c"; @@ -1502,10 +1501,12 @@ d0_aon_i2c1: i2c@51838000 { reg = <0x0 0x51838000 0x0 0x8000>; interrupts = <291>; interrupt-parent = <&plic0>; + numa-node-id = <0>; }; pinctrl: pinctrl@0x51600080 { compatible = "eswin,eic7x-pinctrl"; reg = <0x0 0x51600080 0x0 0x1FFF80>; + numa-node-id = <0>; status = "disabled"; pinctrl_die0_pwm0_default: pwm0-default{ mux { @@ -1526,6 +1527,7 @@ gpio0: gpio@51600000 { #size-cells = <0>; compatible = "snps,dw-apb-gpio"; reg = <0x0 0x51600000 0x0 0x80>; + numa-node-id = <0>; porta: gpio-port@0 { compatible = "snps,dw-apb-gpio-port"; @@ -1574,9 +1576,8 @@ pwm0: pwm@0x50818000 { clock-frequency = <200000000>; resets = <&d0_reset TIMER_RST_CTRL SW_TIMER_RST_N>; reset-names = "rst"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_die0_pwm0_default>; status = "disabled"; + numa-node-id = <0>; }; wdt0: watchdog@0x50800000 { @@ -1589,6 +1590,7 @@ wdt0: watchdog@0x50800000 { interrupts = <87>; interrupt-parent = <&plic0>; status = "disabled"; + numa-node-id = <0>; }; wdt1: watchdog@0x50804000 { @@ -1601,6 +1603,7 @@ wdt1: watchdog@0x50804000 { interrupts = <88>; interrupt-parent = <&plic0>; status = "disabled"; + numa-node-id = <0>; }; wdt2: watchdog@0x50808000 { @@ -1613,6 +1616,7 @@ wdt2: watchdog@0x50808000 { interrupts = <89>; interrupt-parent = <&plic0>; status = "disabled"; + numa-node-id = <0>; }; wdt3: watchdog@0x5080c000 { @@ -1625,6 +1629,7 @@ wdt3: watchdog@0x5080c000 { interrupts = <90>; interrupt-parent = <&plic0>; status = "disabled"; + numa-node-id = <0>; }; timer0: timer@0x51840000 { @@ -1633,6 +1638,7 @@ timer0: timer@0x51840000 { #size-cells = <2>; reg = <0x0 0x51840000 0x0 0x8000>; perf_count = <7>; + numa-node-id = <0>; interrupt-parent = <&plic0>; interrupts = <345>; clock-names = "pclk","timer_aclk"; @@ -1655,6 +1661,7 @@ timer1: timer@0x51848000 { #address-cells = <2>; #size-cells = <2>; reg = <0x0 0x51848000 0x0 0x8000>; + numa-node-id = <0>; interrupt-parent = <&plic0>; interrupts = <346>; clock-names = "pclk","timer_aclk"; @@ -1677,6 +1684,7 @@ timer2: timer@0x51850000 { #address-cells = <2>; #size-cells = <2>; reg = <0x0 0x51850000 0x0 0x8000>; + numa-node-id = <0>; interrupt-parent = <&plic0>; interrupts = <347>; clock-names = "pclk","timer_aclk"; @@ -1699,6 +1707,7 @@ timer3: timer@0x51858000 { #address-cells = <2>; #size-cells = <2>; reg = <0x0 0x51858000 0x0 0x8000>; + numa-node-id = <0>; interrupt-parent = <&plic0>; interrupts = <348>; clock-names = "pclk","timer_aclk","timer3_clk8"; @@ -1729,12 +1738,14 @@ die0_rtc: rtc@51818000 { resets = <&d0_reset RTC_RST_CTRL SW_RTC_RSTN>; reset-names = "rtcrst"; status = "disabled"; + numa-node-id = <0>; }; d0_i2s0: i2s0@50200000 { compatible = "snps,i2s"; - clocks = <&d0_clock WIN2030_CLK_VO_I2S_MCLK>; - clock-names = "mclk"; + clocks = <&d0_clock WIN2030_CLK_VO_I2S_MCLK>, + <&d0_clock WIN2030_APLL_FOUT1>; + clock-names = "mclk", "apll"; #address-cells = <1>; #size-cells = <0>; #sound-dai-cells = <0x00000000>; @@ -1747,12 +1758,14 @@ d0_i2s0: i2s0@50200000 { <&d0_reset VO_PHYRST_CTRL SW_VO_PRSTN>; reset-names = "i2srst", "i2sprst", "voprst"; dma-noncoherent; + numa-node-id = <0>; }; d0_i2s1: i2s1@50210000 { compatible = "snps,i2s"; - clocks = <&d0_clock WIN2030_CLK_VO_I2S_MCLK>; - clock-names = "mclk"; + clocks = <&d0_clock WIN2030_CLK_VO_I2S_MCLK>, + <&d0_clock WIN2030_APLL_FOUT1>; + clock-names = "mclk", "apll"; #address-cells = <1>; #size-cells = <0>; #sound-dai-cells = <0x00000000>; @@ -1765,12 +1778,14 @@ d0_i2s1: i2s1@50210000 { <&d0_reset VO_PHYRST_CTRL SW_VO_PRSTN>; reset-names = "i2srst", "i2sprst", "voprst"; dma-noncoherent; + numa-node-id = <0>; }; d0_i2s2: i2s2@50220000 { compatible = "snps,i2s"; - clocks = <&d0_clock WIN2030_CLK_VO_I2S_MCLK>; - clock-names = "mclk"; + clocks = <&d0_clock WIN2030_CLK_VO_I2S_MCLK>, + <&d0_clock WIN2030_APLL_FOUT1>; + clock-names = "mclk", "apll"; #address-cells = <1>; #size-cells = <0>; #sound-dai-cells = <0x00000000>; @@ -1783,18 +1798,28 @@ d0_i2s2: i2s2@50220000 { <&d0_reset VO_PHYRST_CTRL SW_VO_PRSTN>; reset-names = "i2srst", "i2sprst", "voprst"; dma-noncoherent; + numa-node-id = <0>; + }; + + d0_soundcard: soundcard { + compatible = "simple-audio-card"; + simple-audio-card,name = "Eswin sound card"; + numa-node-id = <0>; }; d0_graphcard0: graphcard0 { compatible = "audio-graph-card"; + numa-node-id = <0>; }; d0_graphcard1: graphcard1 { compatible = "audio-graph-card"; + numa-node-id = <0>; }; d0_graphcard2: graphcard2 { compatible = "audio-graph-card"; + numa-node-id = <0>; }; video_output: display-subsystem@0 { @@ -1807,6 +1832,7 @@ video_output: display-subsystem@0 { dvb_widgets: dvb-subsystem { compatible = "amlogic,dvb_widgets"; status = "disabled"; + numa-node-id = <0>; }; dc: display_control@502c0000 { @@ -1819,8 +1845,12 @@ dc: display_control@502c0000 { <&d0_clock WIN2030_CLK_VO_PIXEL_CLK>, <&d0_clock WIN2030_CLK_VO_ACLK>, <&d0_clock WIN2030_SPLL0_FOUT1>, - <&d0_clock WIN2030_MUX_U_VO_ACLK_ROOT_2MUX1_GFREE>; - clock-names = "cfg_clk", "pix_clk", "axi_clk", "spll0_fout1", "vo_mux"; + <&d0_clock WIN2030_MUX_U_VO_ACLK_ROOT_2MUX1_GFREE>, + <&d0_clock WIN2030_MUX_U_VO_PIXEL_ROOT_2MUX1>, + <&d0_clock WIN2030_SPLL2_FOUT2>, + <&d0_clock WIN2030_VPLL_FOUT1>; + clock-names = "cfg_clk", "pix_clk", "axi_clk", "spll0_fout1", "vo_mux", + "pix_mux", "spll2_fout2", "vpll_fout1"; resets = <&d0_reset VO_RST_CTRL SW_VO_AXI_RSTN>, <&d0_reset VO_RST_CTRL SW_VO_CFG_RSTN>, <&d0_reset VO_RST_CTRL SW_VO_DC_RSTN>, @@ -1926,6 +1956,7 @@ dc_test: dctest@502c0000 { reg = <0x0 0x502c0000 0x0 0x10000>; interrupt-parent = <&plic0>; interrupts = <238>; + numa-node-id = <0>; }; dw_hdmi: hdmi@502a0000 { @@ -1985,6 +2016,7 @@ d0_usbdrd3_0: usb0@50480000 { resets = <&d0_reset HSPDMA_RST_CTRL SW_USB0_VAUX_RSTN>; reset-names = "vaux"; ranges; + numa-node-id = <0>; status = "disabled"; d0_usbdrd_dwc3_0: dwc3@50480000 { compatible = "snps,dwc3"; @@ -2024,6 +2056,7 @@ d0_usbdrd3_1: usb1@50490000 { resets = <&d0_reset HSPDMA_RST_CTRL SW_USB1_VAUX_RSTN>; reset-names = "vaux"; ranges; + numa-node-id = <0>; status = "disabled"; d0_usbdrd_dwc3_1: dwc3@50490000 { compatible = "snps,dwc3"; @@ -2090,6 +2123,7 @@ vi_top_csr: vi_common_top_csr@0x51030000 { id = <0>; #size-cells = <2>; reg = <0x0 0x51030000 0x0 0x10000>; + numa-node-id = <0>; }; @@ -2140,6 +2174,7 @@ dewarp: dewarp@51020000 { <&d0_reset VI_RST_CTRL SW_VI_DWE_RSTN>; reset-names = "axi", "cfg", "dwe"; + operating-points-v2 = <&vi_opp_table>; interrupt-parent = <&plic0>; interrupts = <26 25>; #size-cells = <2>; @@ -2297,6 +2332,7 @@ dc_test: dctest@502c0000 { reg = <0x0 0x502c0000 0x0 0x10000>; interrupt-parent = <&plic0>; interrupts = <238>; + numa-node-id = <0>; }; d0_numa_sample:numa_sample@0 { diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-die1-noc.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-die1-noc.dtsi index e1f621d9889e..1f4a1a693b45 100644 --- a/arch/riscv/boot/dts/eswin/eswin-win2030-die1-noc.dtsi +++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die1-noc.dtsi @@ -29,7 +29,7 @@ d1_cfg_noc:d1_cfg_noc{ interrupt-names = "error"; interrupt-parent = <&plic1>; errlogger,idx = <0 1 3 5>; - + numa-node-id = <1>; sideband_manager@72061000{ compatible = "eswin,win2xxx-noc-sideband-manager"; reg = <0 0x72061000 0 0x10>; @@ -273,6 +273,7 @@ d1_llc_noc:d1_llc_noc@72081400 { #address-cells = <2>; #size-cells = <2>; ranges; + numa-node-id = <1>; reg = <0 0x72081400 0 0x4000>; interrupts = <441>; interrupt-names = "error"; @@ -548,6 +549,7 @@ d1_sys_noc:d1_sys_noc@72002C00 { #address-cells = <2>; #size-cells = <2>; ranges; + numa-node-id = <1>; reg = <0 0x72002C00 0 0x4000>; interrupts = <431>; interrupt-names = "error"; @@ -2220,6 +2222,7 @@ d1_media_noc:d1_media_noc@72021400 { #address-cells = <2>; #size-cells = <2>; ranges; + numa-node-id = <1>; reg = <0 0x72021400 0 0x4000>; interrupts = <454>; interrupt-names = "error"; @@ -2530,6 +2533,7 @@ d1_realtime_noc:d1_realtime_noc@72041400 { #address-cells = <2>; #size-cells = <2>; ranges; + numa-node-id = <1>; reg = <0 0x72041400 0 0x4000>; interrupts = <448>; interrupt-names = "error"; diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi b/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi index 7ef1be2f7a36..725e811f0825 100644 --- a/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi +++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi @@ -31,77 +31,6 @@ #include / { - d1_cpu_opp_table: opp-table1 { - compatible = "operating-points-v2"; - opp-shared; - - opp-24000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-100000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-200000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-400000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-500000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-600000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-700000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-800000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-900000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-1000000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-1200000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-1300000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - opp-1400000000 { - opp-hz = /bits/ 64 ; - opp-microvolt = <800000>; - clock-latency-ns = <70000>; - }; - }; - thermal-zones { d1_thermal0 { polling-delay-passive = <500>; /*ms*/ @@ -110,9 +39,10 @@ d1_thermal0 { thermal-sensors = <&d1_pvt0>; trips { + /* d1_threshold: trip-point0 { - temperature = <60000>; /* DC*1000 */ - hysteresis = <1000>; /* DC*1000 */ + temperature = <60000>; + hysteresis = <1000>; type = "passive"; }; d1_target: trip-point1 { @@ -120,14 +50,16 @@ d1_target: trip-point1 { hysteresis = <1000>; type = "passive"; }; + */ d1_crit: trip-point2 { - temperature = <110000>; + temperature = <88000>; hysteresis = <0>; type = "critical"; }; }; cooling-maps { + /* map0 { trip = <&d1_target>; contribution = <1024>; @@ -139,14 +71,15 @@ map0 { }; map1 { trip = <&d1_target>; - contribution = <1024>; /*TBD*/ + contribution = <1024>; cooling-device = <&d1_npu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; map2 { trip = <&d1_target>; - contribution = <1024>; /*TBD*/ + contribution = <1024>; cooling-device = <&d1_gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>; }; + */ }; }; }; @@ -229,6 +162,7 @@ d1_noc_wdt:noc@71810324 { <421>, <422>, <423>, <424>, <425>, <426>; eswin,syscrg_csr = <&d1_sys_crg 0x100 0xffff>; //timeout paramerter + numa-node-id = <1>; }; }; @@ -239,10 +173,12 @@ d1_sys_crg: sys-crg@71828000 { d1_reset: reset-controller { compatible = "eswin,win2030-reset"; #reset-cells = <2>; + numa-node-id = <1>; }; d1_clock: clock-controller { compatible = "eswin,win2030-clock"; #clock-cells = <1>; + numa-node-id = <1>; }; }; @@ -250,6 +186,7 @@ d1_hsp_sp_csr: hsp_sp_top_csr@0x70440000 { compatible = "eswin,win2030-hsp-sp-csr", "syscon"; #size-cells = <2>; reg = <0x0 0x70440000 0x0 0x2000>; + numa-node-id = <1>; }; smmu1: iommu@70c00000 { @@ -441,6 +378,7 @@ noc { #address-cells = <2>; #size-cells = <2>; ranges; + numa-node-id = <1>; #include "eswin-win2030-die1-noc.dtsi" }; vdec1: video-decoder1@70100000 { @@ -556,6 +494,7 @@ d1_mbox0: mbox@70a00000 { lock-bit = ; irq-bit = ; dma-noncoherent; + numa-node-id = <1>; }; /*mailbox between u84 & lpcpu*/ @@ -575,6 +514,7 @@ d1_mbox1: mbox@70a20000 { lock-bit = ; irq-bit = ; dma-noncoherent; + numa-node-id = <1>; }; /*mailbox between u84 & npu_0*/ @@ -594,6 +534,7 @@ d1_mbox2: mbox@70a40000 { lock-bit = ; irq-bit = ; dma-noncoherent; + numa-node-id = <1>; }; /*mailbox between u84 & npu_1*/ @@ -613,6 +554,7 @@ d1_mbox3: mbox@70a60000 { lock-bit = ; irq-bit = ; dma-noncoherent; + numa-node-id = <1>; }; /*mailbox between u84 & dsp_0*/ @@ -632,6 +574,7 @@ d1_mbox4: mbox@70a80000 { lock-bit = ; irq-bit = ; dma-noncoherent; + numa-node-id = <1>; }; /*mailbox between u84 & dsp_1*/ @@ -651,6 +594,7 @@ d1_mbox5: mbox@70aa0000 { lock-bit = ; irq-bit = ; dma-noncoherent; + numa-node-id = <1>; }; /*mailbox between u84 & dsp_2*/ @@ -670,6 +614,7 @@ d1_mbox6: mbox@70ac0000 { lock-bit = ; irq-bit = ; dma-noncoherent; + numa-node-id = <1>; }; /*mailbox between u84 & dsp_3*/ @@ -689,6 +634,7 @@ d1_mbox7: mbox@70ae0000 { lock-bit = ; irq-bit = ; dma-noncoherent; + numa-node-id = <1>; }; d1_ipc_scpu:ipc@1 { @@ -742,6 +688,7 @@ d1_pvt0: pvt@0x70b00000 { #thermal-sensor-cells = <0>; status = "disabled"; label = "d1_pvt0"; + numa-node-id = <1>; }; d1_pvt1: pvt@0x72360000 { compatible = "eswin,eswin-pvt-ddr"; @@ -756,6 +703,7 @@ d1_pvt1: pvt@0x72360000 { interrupt-parent = <&plic1>; status = "disabled"; label = "d1_pvt1"; + numa-node-id = <1>; }; d1_fan_control: fan_control@70b50000 { @@ -773,6 +721,7 @@ d1_fan_control: fan_control@70b50000 { pwms = <&d1_pwm0 0 100000>; status = "disabled"; label = "d1_fan_control"; + numa-node-id = <1>; }; d1_i2c0: i2c@70950000 { @@ -797,6 +746,7 @@ d1_i2c0: i2c@70950000 { * 6 : i2c0 dma controller sel bit in sys_son dma_cfg reg(offset 0x370) */ dmas = <&d1_aon_dmac 24 6>, <&d1_aon_dmac 25 6>; + numa-node-id = <1>; }; d1_i2c1: i2c@70960000 { compatible = "snps,designware-i2c"; @@ -811,6 +761,7 @@ d1_i2c1: i2c@70960000 { interrupts = <106>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_i2c2: i2c@70970000 { compatible = "snps,designware-i2c"; @@ -825,6 +776,7 @@ d1_i2c2: i2c@70970000 { interrupts = <107>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_i2c3: i2c@70980000 { compatible = "snps,designware-i2c"; @@ -839,6 +791,7 @@ d1_i2c3: i2c@70980000 { interrupts = <108>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_i2c4: i2c@70990000 { compatible = "snps,designware-i2c"; @@ -853,6 +806,7 @@ d1_i2c4: i2c@70990000 { interrupts = <109>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_i2c5: i2c@709a0000 { compatible = "snps,designware-i2c"; @@ -867,6 +821,7 @@ d1_i2c5: i2c@709a0000 { interrupts = <110>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_i2c6: i2c@709b0000 { compatible = "snps,designware-i2c"; @@ -881,6 +836,7 @@ d1_i2c6: i2c@709b0000 { interrupts = <111>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_i2c7: i2c@709c0000 { compatible = "snps,designware-i2c"; @@ -895,6 +851,7 @@ d1_i2c7: i2c@709c0000 { interrupts = <112>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_i2c8: i2c@709d0000 { compatible = "snps,designware-i2c"; @@ -909,6 +866,7 @@ d1_i2c8: i2c@709d0000 { interrupts = <113>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_i2c9: i2c@709e0000 { compatible = "snps,designware-i2c"; @@ -923,6 +881,7 @@ d1_i2c9: i2c@709e0000 { interrupts = <114>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_aon_i2c0: i2c@71830000 { @@ -946,6 +905,7 @@ d1_aon_i2c0: i2c@71830000 { * 0xff : no need to select to dma controller */ dmas = <&d1_aon_dmac 41 0xff>, <&d1_aon_dmac 42 0xff>; + numa-node-id = <1>; }; d1_aon_i2c1: i2c@71838000 { compatible = "snps,designware-i2c"; @@ -959,6 +919,7 @@ d1_aon_i2c1: i2c@71838000 { reg = <0x0 0x71838000 0x0 0x10000>; interrupts = <291>; interrupt-parent = <&plic1>; + numa-node-id = <1>; }; d1_npu: eswin-npu@71c00000 { @@ -966,7 +927,7 @@ d1_npu: eswin-npu@71c00000 { reg = <0x0 0x71c00000 0x0 0x400000>; interrupt-parent = <&plic1>; interrupts = <387 16>; - spram-region = <&npu1_reserved>; + /* spram-region = <&npu1_reserved>;*/ #size-cells = <2>; dma-ranges = <0x1 0x0 0x0 0xc0000000 0x1ff 0x0>; iommus = <&smmu1 WIN2030_SID_NPU_DMA>; @@ -977,11 +938,17 @@ d1_npu: eswin-npu@71c00000 { clocks = <&d1_clock WIN2030_CLK_NPU_ACLK>, <&d1_clock WIN2030_CLK_NPU_CFG_CLK>, <&d1_clock WIN2030_CLK_NPU_CLK>, - <&d1_clock WIN2030_CLK_NPU_E31_CLK>; - clock-names = "aclk", "cfg_clk", "core_clk", "e31_core_clk"; + <&d1_clock WIN2030_CLK_NPU_E31_CLK>, + <&d1_clock WIN2030_MUX_U_NPU_CORE_3MUX1_GFREE>, + <&d1_clock WIN2030_SPLL2_FOUT2>, + <&d1_clock WIN2030_SPLL1_FOUT1>; + + clock-names = "aclk", "cfg_clk", "core_clk", "e31_core_clk", "mux_u_npu_core_3mux1_gfree", "fixed_rate_clk_spll2_fout2", + "fixed_rate_clk_spll1_fout1"; resets = <&d1_reset NPU_RST_CTRL SW_NPU_E31CORE_RSTN>; reset-names = "e31_core"; + operating-points-v2 = <&npu_opp_table>; numa-node-id = <1>; firmware-name = "eic7700_die1_e31_fw"; @@ -1033,6 +1000,7 @@ d1_gpu: gpu@71400000 { interrupt-parent = <&plic1>; interrupts = <15>; dma-noncoherent; + numa-node-id = <1>; #cooling-cells = <2>; dynamic-power-coefficient = <0>; /*TBD*/ @@ -1061,6 +1029,7 @@ d1_pinctrl: pinctrl@0x71600080 { compatible = "eswin,eic7x-pinctrl"; reg = <0x0 0x71600080 0x0 0x1FFF80>; status = "disabled"; + numa-node-id = <1>; d1_pinctrl_pwm0_default: pwm0-default{ mux{ groups = "pwm0_group"; @@ -1104,6 +1073,7 @@ d1_gpio0: gpio@71600000 { #size-cells = <0>; compatible = "snps,dw-apb-gpio"; reg = <0x0 0x71600000 0x0 0x80>; + numa-node-id = <1>; d1_porta: gpio-port@0 { compatible = "snps,dw-apb-gpio-port"; @@ -1148,6 +1118,8 @@ d1_timer0: timer@0x71840000 { #address-cells = <2>; #size-cells = <2>; reg = <0x0 0x71840000 0x0 0x8000>; + perf_count = <7>; + numa-node-id = <1>; interrupt-parent = <&plic1>; interrupts = <345>; clock-names = "pclk","timer_aclk"; @@ -1170,6 +1142,7 @@ d1_timer1: timer@0x71848000 { #address-cells = <2>; #size-cells = <2>; reg = <0x0 0x71848000 0x0 0x8000>; + numa-node-id = <1>; interrupt-parent = <&plic1>; interrupts = <346>; clock-names = "pclk","timer_aclk"; @@ -1193,6 +1166,7 @@ d1_timer2: timer@0x71850000 { #address-cells = <2>; #size-cells = <2>; reg = <0x0 0x71850000 0x0 0x8000>; + numa-node-id = <1>; interrupt-parent = <&plic1>; interrupts = <347>; clock-names = "pclk","timer_aclk"; @@ -1215,6 +1189,7 @@ d1_timer3: timer@0x71858000 { #address-cells = <2>; #size-cells = <2>; reg = <0x0 0x71858000 0x0 0x8000>; + numa-node-id = <1>; interrupt-parent = <&plic1>; interrupts = <348>; clock-names = "pclk","timer_aclk","timer3_clk8"; @@ -1245,12 +1220,14 @@ d1_pwm0: pwm@0x70818000 { pinctrl-names = "default"; pinctrl-0 = <&d1_pinctrl_pwm0_default &d1_pinctrl_pwm1_default &d1_pinctrl_pwm2_default>; status = "disabled"; + numa-node-id = <1>; }; d1_i2s0: i2s0@70200000 { compatible = "snps,i2s"; - clocks = <&d1_clock WIN2030_CLK_VO_I2S_MCLK>; - clock-names = "mclk"; + clocks = <&d1_clock WIN2030_CLK_VO_I2S_MCLK>, + <&d1_clock WIN2030_APLL_FOUT1>; + clock-names = "mclk", "apll"; #address-cells = <1>; #size-cells = <0>; #sound-dai-cells = <0x00000000>; @@ -1263,12 +1240,14 @@ d1_i2s0: i2s0@70200000 { <&d1_reset VO_PHYRST_CTRL SW_VO_PRSTN>; reset-names = "i2srst", "i2sprst", "voprst"; dma-noncoherent; + numa-node-id = <1>; }; d1_i2s1: i2s1@70210000 { compatible = "snps,i2s"; - clocks = <&d1_clock WIN2030_CLK_VO_I2S_MCLK>; - clock-names = "mclk"; + clocks = <&d1_clock WIN2030_CLK_VO_I2S_MCLK>, + <&d1_clock WIN2030_APLL_FOUT1>; + clock-names = "mclk", "apll"; #address-cells = <1>; #size-cells = <0>; #sound-dai-cells = <0x00000000>; @@ -1281,12 +1260,14 @@ d1_i2s1: i2s1@70210000 { <&d1_reset VO_PHYRST_CTRL SW_VO_PRSTN>; reset-names = "i2srst", "i2sprst", "voprst"; dma-noncoherent; + numa-node-id = <1>; }; d1_i2s2: i2s@70220000 { compatible = "snps,i2s"; - clocks = <&d1_clock WIN2030_CLK_VO_I2S_MCLK>; - clock-names = "mclk"; + clocks = <&d1_clock WIN2030_CLK_VO_I2S_MCLK>, + <&d1_clock WIN2030_APLL_FOUT1>; + clock-names = "mclk", "apll"; #address-cells = <1>; #size-cells = <0>; #sound-dai-cells = <0x00000000>; @@ -1299,18 +1280,22 @@ d1_i2s2: i2s@70220000 { <&d1_reset VO_PHYRST_CTRL SW_VO_PRSTN>; reset-names = "i2srst", "i2sprst", "voprst"; dma-noncoherent; + numa-node-id = <1>; }; d1_graphcard0: graphcard4 { compatible = "audio-graph-card"; + numa-node-id = <1>; }; d1_graphcard1: graphcard5 { compatible = "audio-graph-card"; + numa-node-id = <1>; }; d1_graphcard2: graphcard6 { compatible = "audio-graph-card"; + numa-node-id = <1>; }; d1_dsp_subsys:dsp_subsys@72280400 { @@ -1331,6 +1316,7 @@ d1_dsp_subsys:dsp_subsys@72280400 { <&d1_reset DSP_RST_CTRL SW_DSP_DIV_RSTN_2>, <&d1_reset DSP_RST_CTRL SW_DSP_DIV_RSTN_3>; reset-names = "axi", "cfg", "div4", "div_0", "div_1", "div_2","div_3"; + numa-node-id = <1>; d1_dsp0:es_dsp@0 { #address-cells = <1>; #size-cells = <1>; @@ -1460,6 +1446,7 @@ d1_rtc: rtc@71818000 { resets = <&d1_reset RTC_RST_CTRL SW_RTC_RSTN>; reset-names = "rtcrst"; status = "disabled"; + numa-node-id = <1>; }; d1_pcie: pcie@0x74000000 { @@ -1527,11 +1514,12 @@ d1_gmac0: ethernet@70400000 { clock-names = "app", "stmmaceth","tx"; resets = <&d1_reset HSPDMA_RST_CTRL SW_HSP_ETH0_ARSTN>; reset-names = "ethrst"; - iommus = <&smmu1 WIN2030_SID_ETH0>; + //iommus = <&smmu1 WIN2030_SID_ETH0>; tbus = ; dma-noncoherent; eswin,hsp_sp_csr = <&d1_hsp_sp_csr 0x1030 0x100 0x108>; eswin,syscrg_csr = <&d1_sys_crg 0x148 0x14c>; + eswin,dly_hsp_reg = <0x114 0x118 0x11c>; snps,axi-config = <&d1_stmmac_axi_setup>; d1_stmmac_axi_setup: stmmac-axi-config { snps,blen = <0 0 0 0 16 8 4>; @@ -1557,11 +1545,12 @@ d1_gmac1: ethernet@70410000 { clock-names = "app", "stmmaceth","tx"; resets = <&d1_reset HSPDMA_RST_CTRL SW_HSP_ETH1_ARSTN>; reset-names = "ethrst"; - iommus = <&smmu1 WIN2030_SID_ETH1>; + //iommus = <&smmu1 WIN2030_SID_ETH1>; tbus = ; dma-noncoherent; eswin,hsp_sp_csr = <&d1_hsp_sp_csr 0x1034 0x200 0x208>; eswin,syscrg_csr = <&d1_sys_crg 0x148 0x14c>; + eswin,dly_hsp_reg = <0x214 0x218 0x21c>; snps,axi-config = <&d1_stmmac_axi_setup_gmac1>; d1_stmmac_axi_setup_gmac1: stmmac-axi-config { snps,blen = <0 0 0 0 16 8 4>; @@ -1725,6 +1714,7 @@ d1_bootspi: spi@71800000 { spi-max-frequency = <4800000>; reg-io-width = <4>; status = "disabled"; + numa-node-id = <1>; }; d1_video_output: display-subsystem@1 { @@ -1744,8 +1734,12 @@ d1_dc: display_control@702c0000 { <&d1_clock WIN2030_CLK_VO_PIXEL_CLK>, <&d1_clock WIN2030_CLK_VO_ACLK>, <&d1_clock WIN2030_SPLL0_FOUT1>, - <&d1_clock WIN2030_MUX_U_VO_ACLK_ROOT_2MUX1_GFREE>; - clock-names = "cfg_clk", "pix_clk", "axi_clk", "spll0_fout1", "vo_mux"; + <&d1_clock WIN2030_MUX_U_VO_ACLK_ROOT_2MUX1_GFREE>, + <&d1_clock WIN2030_MUX_U_VO_PIXEL_ROOT_2MUX1>, + <&d1_clock WIN2030_SPLL2_FOUT2>, + <&d1_clock WIN2030_VPLL_FOUT1>; + clock-names = "cfg_clk", "pix_clk", "axi_clk", "spll0_fout1", "vo_mux", + "pix_mux", "spll2_fout2", "vpll_fout1"; resets = <&d1_reset VO_RST_CTRL SW_VO_AXI_RSTN>, <&d1_reset VO_RST_CTRL SW_VO_CFG_RSTN>, <&d1_reset VO_RST_CTRL SW_VO_DC_RSTN>, @@ -1852,6 +1846,7 @@ d1_dc_test: dctest@702c0000 { reg = <0x0 0x702c0000 0x0 0x10000>; interrupt-parent = <&plic1>; interrupts = <238>; + numa-node-id = <1>; }; d1_dw_hdmi: hdmi@702a0000 { @@ -1909,6 +1904,7 @@ d1_wdt0: watchdog@0x70800000 { interrupts = <87>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_wdt1: watchdog@0x70804000 { @@ -1921,6 +1917,7 @@ d1_wdt1: watchdog@0x70804000 { interrupts = <88>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_wdt2: watchdog@0x70808000 { @@ -1933,6 +1930,7 @@ d1_wdt2: watchdog@0x70808000 { interrupts = <89>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_wdt3: watchdog@0x7080c000 { @@ -1945,6 +1943,7 @@ d1_wdt3: watchdog@0x7080c000 { interrupts = <90>; interrupt-parent = <&plic1>; status = "disabled"; + numa-node-id = <1>; }; d1_gc820: g2d@70140000 { @@ -2016,6 +2015,7 @@ d1_sdhci_emmc: mmc@70450000 { d1_graphcard: graphcard { compatible = "audio-graph-card"; + numa-node-id = <1>; }; d1_usbdrd3_0: usb0@70480000 { @@ -2031,6 +2031,7 @@ d1_usbdrd3_0: usb0@70480000 { reset-names = "vaux"; ranges; status = "disabled"; + numa-node-id = <1>; d1_usbdrd_dwc3_0: dwc3@70480000 { compatible = "snps,dwc3"; reg = <0x0 0x70480000 0x0 0x10000>; @@ -2070,6 +2071,7 @@ d1_usbdrd3_1: usb1@70490000 { reset-names = "vaux"; ranges; status = "disabled"; + numa-node-id = <1>; d1_usbdrd_dwc3_1: dwc3@70490000 { compatible = "snps,dwc3"; reg = <0x0 0x70490000 0x0 0x10000>; @@ -2134,6 +2136,7 @@ d1_vi_top_csr: vi_common_top_csr@0x71030000 { id = <0>; #size-cells = <2>; reg = <0x0 0x71030000 0x0 0x10000>; + numa-node-id = <1>; }; d1_isp_0: isp@0x71000000 { @@ -2334,6 +2337,7 @@ d1_dc_test: dctest@702c0000 { reg = <0x0 0x702c0000 0x0 0x10000>; interrupt-parent = <&plic1>; interrupts = <238>; + numa-node-id = <1>; }; d1_numa_sample:numa_sample@1 { diff --git a/arch/riscv/configs/eic7700_defconfig b/arch/riscv/configs/eic7700_defconfig index cb9f99ea41b6..e85ffec6ac9f 100644 --- a/arch/riscv/configs/eic7700_defconfig +++ b/arch/riscv/configs/eic7700_defconfig @@ -476,6 +476,7 @@ CONFIG_THERMAL_EMULATION=y CONFIG_WATCHDOG=y CONFIG_DW_WATCHDOG=y CONFIG_REGULATOR=y +CONFIG_REGULATOR_ES5340=y CONFIG_REGULATOR_MPQ8785=y CONFIG_REGULATOR_PCA9450=y CONFIG_MEDIA_SUPPORT=y @@ -754,7 +755,8 @@ CONFIG_ARCH_ESWIN_EIC770X_SOC_FAMILY=y CONFIG_ESWIN_DSP=m CONFIG_ESWIN_NPU=m CONFIG_PM_DEVFREQ=y -CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND=y +CONFIG_DEVFREQ_GOV_USERSPACE=y +CONFIG_PM_DEVFREQ_EVENT=y CONFIG_EXTCON=y CONFIG_MEMORY=y CONFIG_ESWIN_BUDDY=y @@ -763,6 +765,7 @@ CONFIG_ESWIN_RSVMEM_HEAP=y CONFIG_ESWIN_MMZ_VB=y CONFIG_ESWIN_DEV_DMA_BUF=y CONFIG_ESWIN_IOMMU_RSV=y +CONFIG_ESWIN_DMA_MEMCP=y CONFIG_PWM=y CONFIG_PWM_ESWIN=y CONFIG_RESET_ESWIN_WIN2030=y diff --git a/arch/riscv/configs/eic7702_defconfig b/arch/riscv/configs/eic7702_defconfig index 830481fffc7e..3cecf50b5503 100644 --- a/arch/riscv/configs/eic7702_defconfig +++ b/arch/riscv/configs/eic7702_defconfig @@ -10,6 +10,7 @@ CONFIG_PREEMPT_VOLUNTARY=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_NUMA_BALANCING=y +# CONFIG_NUMA_BALANCING_DEFAULT_ENABLED is not set CONFIG_CGROUPS=y CONFIG_MEMCG=y CONFIG_BLK_CGROUP=y @@ -632,9 +633,9 @@ CONFIG_DRM_SIMPLE_BRIDGE=y CONFIG_DRM_TOSHIBA_TC358768=m CONFIG_DRM_SIMPLEDRM=m CONFIG_DRM_ESWIN=y +CONFIG_ESWIN_VIRTUAL_DISPLAY=y CONFIG_ESWIN_MMU=y CONFIG_ESWIN_DW_HDMI=y -CONFIG_ESWIN_VIRTUAL_DISPLAY=y CONFIG_DW_HDMI_I2S_AUDIO=y CONFIG_DW_HDMI_CEC=y CONFIG_DRM_IMG_VOLCANIC=m @@ -809,6 +810,7 @@ CONFIG_CRYPTO_HMAC=m CONFIG_CRYPTO_MD5=y CONFIG_CRYPTO_SHA512=m CONFIG_CRYPTO_DEV_VIRTIO=y +CONFIG_CRYPTO_DEV_ESWIN_EIC770x=y CONFIG_CRC_ITU_T=y CONFIG_CRC7=y CONFIG_XZ_DEC=y @@ -819,7 +821,6 @@ CONFIG_CONSOLE_LOGLEVEL_DEFAULT=15 CONFIG_CONSOLE_LOGLEVEL_QUIET=15 CONFIG_MESSAGE_LOGLEVEL_DEFAULT=7 CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_FS=y CONFIG_DEBUG_PAGEALLOC=y CONFIG_SCHED_STACK_END_CHECK=y CONFIG_DEBUG_VM=y diff --git a/arch/riscv/configs/win2030_defconfig b/arch/riscv/configs/win2030_defconfig index c2c4f5a620b7..25cac9c13b62 100644 --- a/arch/riscv/configs/win2030_defconfig +++ b/arch/riscv/configs/win2030_defconfig @@ -748,6 +748,7 @@ CONFIG_ESWIN_RSVMEM_HEAP=y CONFIG_ESWIN_MMZ_VB=y CONFIG_ESWIN_DEV_DMA_BUF=y CONFIG_ESWIN_IOMMU_RSV=y +CONFIG_ESWIN_DMA_MEMCP=y CONFIG_PWM=y CONFIG_PWM_ESWIN=y CONFIG_RESET_ESWIN_WIN2030=y diff --git a/drivers/clk/eswin/clk-win2030.c b/drivers/clk/eswin/clk-win2030.c index ccb7dade5475..93cb6c6c8507 100755 --- a/drivers/clk/eswin/clk-win2030.c +++ b/drivers/clk/eswin/clk-win2030.c @@ -24,7 +24,7 @@ #include #include #include - +#include #include #include @@ -1170,6 +1170,42 @@ static void special_div_table_init(struct clk_div_table *table, int table_size) return; } + +static int eswin_cpu_clk_init(struct platform_device *pdev) +{ + struct clk *cpu_clk; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + u32 default_freq; + int ret = 0; + int numa_id; + char name[128] = {0}; + + ret = of_property_read_u32(np, "cpu-default-frequency", &default_freq); + if (ret) { + dev_info(dev, "cpu-default-frequency not set\n"); + return ret; + } + numa_id = dev_to_node(dev->parent); + if (numa_id < 0) { + sprintf(name, "%s", "clk_cpu_ext_src_core_clk_0"); + } else { + sprintf(name, "d%d_%s", numa_id, "clk_cpu_ext_src_core_clk_0"); + } + cpu_clk = __clk_lookup(name); + if (!cpu_clk) { + dev_err(dev, "Failed to lookup CPU clock\n"); + return -EINVAL; + } + ret = clk_set_rate(cpu_clk, default_freq); + if (ret) { + dev_err(dev, "Failed to set CPU frequency: %d\n", ret); + return ret; + } + dev_info(dev, "CPU frequency set to %u Hz\n", default_freq); + return 0; +} + static int eswin_clk_probe(struct platform_device *pdev) { struct eswin_clock_data *clk_data; @@ -1207,6 +1243,9 @@ static int eswin_clk_probe(struct platform_device *pdev) eswin_clk_register_gate(win2030_gate_clks, ARRAY_SIZE(win2030_gate_clks), clk_data); eswin_clk_register_clk(win2030_clks, ARRAY_SIZE(win2030_clks), clk_data); + + eswin_cpu_clk_init(pdev); + return 0; } diff --git a/drivers/clocksource/timer-eswin.c b/drivers/clocksource/timer-eswin.c index a00a686bc0ec..f7003459da04 100644 --- a/drivers/clocksource/timer-eswin.c +++ b/drivers/clocksource/timer-eswin.c @@ -1,8 +1,22 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) ESWIN Electronics Co.Ltd + * ESWIN timer driver * - * Eswin timer driver + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: Xuxiang */ #include @@ -44,10 +58,11 @@ struct eswin_timer { struct resource *mem; void __iomem *mmio_base; u32 perf_count; + u32 numa_id; }; -static struct eswin_timer *perf_timer = NULL; -static void __iomem *perf_cnt_base = NULL; +static struct eswin_timer *perf_timer[2] = {NULL, NULL}; +static void __iomem *perf_cnt_base[2] = {NULL, NULL}; static inline u32 eswin_readl(struct eswin_timer *timer, unsigned long offs) { @@ -163,27 +178,56 @@ static int timer_mmap(struct file *file, struct vm_area_struct *vma) { struct resource *res; u64 base; - if (perf_timer == NULL) { + if (perf_timer[0] == NULL) { return -EIO; } - res = perf_timer->mem; + res = perf_timer[0]->mem; - base = res->start + perf_timer->perf_count * 0x14; + base = res->start + perf_timer[0]->perf_count * 0x14; remap_pfn_range(vma, vma->vm_start, base >> 12, vma->vm_end - vma->vm_start, vma->vm_page_prot); return 0; } -static struct file_operations timer_fops = { - .owner = THIS_MODULE, - .mmap = timer_mmap, +static int timer_mmap_die1(struct file *file, struct vm_area_struct *vma) +{ + struct resource *res; + u64 base; + if (perf_timer[1] == NULL) { + return -EIO; + } + + res = perf_timer[1]->mem; + + base = res->start + perf_timer[1]->perf_count * 0x14; + remap_pfn_range(vma, vma->vm_start, base >> 12, + vma->vm_end - vma->vm_start, vma->vm_page_prot); + return 0; +} + +static struct file_operations timer_fops[2] = { + { + .owner = THIS_MODULE, + .mmap = timer_mmap, + }, + { + .owner = THIS_MODULE, + .mmap = timer_mmap_die1, + }, }; -static struct miscdevice timer_misc = { - .minor = MISC_DYNAMIC_MINOR, - .name = "perf_count", - .fops = &timer_fops, +static struct miscdevice timer_misc[2] = { + { + .minor = MISC_DYNAMIC_MINOR, + .name = "perf_count", + .fops = &timer_fops[0], + }, + { + .minor = MISC_DYNAMIC_MINOR, + .name = "perf_count_die1", + .fops = &timer_fops[1], + }, }; /* @@ -195,9 +239,9 @@ static struct miscdevice timer_misc = { * resolution: about 42ns per cnt. So the max time that will not overflow is 42 * 0xFFFF_FFFF ~= 180s */ -u32 get_perf_timer_cnt(void) +u32 get_perf_timer_cnt(u32 numa_id) { - return APBTMR_MAX_CNT - readl(perf_cnt_base); + return APBTMR_MAX_CNT - readl(perf_cnt_base[numa_id]); } EXPORT_SYMBOL(get_perf_timer_cnt); @@ -208,22 +252,21 @@ static int init_timer_perf_counter(struct eswin_timer *time, u32 chan) time->perf_count = chan; eswin_writel(time, APBTMR_MAX_CNT, chan * APBTMR_EACH_OFS + APBTMR_N_LOAD_COUNT); eswin_writel(time, 0x7, chan * APBTMR_EACH_OFS + APBTMR_N_CONTROL); - ret = misc_register(&timer_misc); - perf_timer = time; - perf_cnt_base = perf_timer->mmio_base + chan * APBTMR_EACH_OFS + APBTMR_N_CURRENT_VALUE; + ret = misc_register(&timer_misc[time->numa_id]); + perf_timer[time->numa_id] = time; + perf_cnt_base[time->numa_id] = perf_timer[time->numa_id]->mmio_base + chan * APBTMR_EACH_OFS + APBTMR_N_CURRENT_VALUE; return 0; } static int eswin_timer_probe(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; + struct device_node *np = pdev->dev.of_node; struct eswin_timer *time; struct resource *res; int error, irq, ret; u32 val; - dev_err(&pdev->dev, "eswin_timer_probe\n"); + dev_info(&pdev->dev, "eswin_timer_probe\n"); /*add eswin timer*/ time = devm_kzalloc(&pdev->dev, sizeof(struct eswin_timer), GFP_KERNEL); if (!time) @@ -236,6 +279,12 @@ static int eswin_timer_probe(struct platform_device *pdev) } time->mem = res; + ret = device_property_read_u32(&pdev->dev, "numa-node-id", &time->numa_id); + if (0 != ret) { + dev_err(&pdev->dev, "failed to get numa node id\n"); + return ret; + } + time->mmio_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(time->mmio_base)) return PTR_ERR(time->mmio_base); @@ -262,7 +311,7 @@ static int eswin_timer_probe(struct platform_device *pdev) init_timer_perf_counter(time, val); } - dev_err(&pdev->dev, "eswin_timer_probe success\n"); + dev_info(&pdev->dev, "eswin_timer_probe success\n"); return 0; } diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c index 84ae708fafe7..c5634708c9a4 100644 --- a/drivers/dma-buf/dma-heap.c +++ b/drivers/dma-buf/dma-heap.c @@ -300,6 +300,7 @@ struct dma_heap *dma_heap_add(const struct dma_heap_export_info *exp_info) kfree(heap); return err_ret; } +EXPORT_SYMBOL(dma_heap_add); static char *dma_heap_devnode(const struct device *dev, umode_t *mode) { diff --git a/drivers/gpu/drm/eswin/Makefile b/drivers/gpu/drm/eswin/Makefile index 09cb7092e2e5..b96f169eedfe 100644 --- a/drivers/gpu/drm/eswin/Makefile +++ b/drivers/gpu/drm/eswin/Makefile @@ -13,7 +13,7 @@ es_drm-objs := es_dc_hw.o \ es_drm-$(CONFIG_ESWIN_VIRTUAL_DISPLAY) += es_virtual.o es_drm-$(CONFIG_ESWIN_MMU) += es_dc_mmu.o -es_drm-$(CONFIG_ESWIN_DW_HDMI) += eswin_dw_hdmi.o dw-hdmi.o +es_drm-$(CONFIG_ESWIN_DW_HDMI) += es_dw_hdmi.o dw-hdmi.o es_drm-$(CONFIG_DW_HDMI_I2S_AUDIO) += dw_hdmi_i2s_audio.o es_drm-$(CONFIG_DW_HDMI_CEC) += dw_hdmi_cec.o diff --git a/drivers/gpu/drm/eswin/dw-hdmi.c b/drivers/gpu/drm/eswin/dw-hdmi.c index c301d589a508..82a3cc3f69aa 100644 --- a/drivers/gpu/drm/eswin/dw-hdmi.c +++ b/drivers/gpu/drm/eswin/dw-hdmi.c @@ -22,7 +22,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Authors: Eswin Driver team + * Authors: DengLei */ #include #include @@ -2549,6 +2549,9 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi, dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic); } + dev_dbg(hdmi->dev, "mode clock:%d, hdisplay:%d, htotal:%d, vdisplay:%d, vtotal:%d\n", + mode->clock, mode->hdisplay, mode->htotal, mode->vdisplay, mode->vtotal); + if (hdmi->plat_data->get_enc_out_encoding) hdmi->hdmi_data.enc_out_encoding = hdmi->plat_data->get_enc_out_encoding(data); @@ -3370,7 +3373,7 @@ dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge, if (mode->clock != 594000 && mode->clock != 297000 && mode->clock != 148500 && mode->clock != 108000 && mode->clock != 74250 && mode->clock != 54000 && - mode->clock != 27000) { + mode->clock != 27000 && mode->clock != 513820) { return MODE_NOCLOCK; } diff --git a/drivers/gpu/drm/eswin/dw-hdmi.h b/drivers/gpu/drm/eswin/dw-hdmi.h index dcfeaada7f1d..9304c5865aee 100644 --- a/drivers/gpu/drm/eswin/dw-hdmi.h +++ b/drivers/gpu/drm/eswin/dw-hdmi.h @@ -18,7 +18,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Authors: Eswin Driver team + * Authors: DengLei */ #ifndef __DW_HDMI_H__ #define __DW_HDMI_H__ diff --git a/drivers/gpu/drm/eswin/dw_hdmi_audio.h b/drivers/gpu/drm/eswin/dw_hdmi_audio.h index 97e0d9f02490..105f5e71babd 100644 --- a/drivers/gpu/drm/eswin/dw_hdmi_audio.h +++ b/drivers/gpu/drm/eswin/dw_hdmi_audio.h @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Authors: Eswin Driver team + * Authors: DengLei */ #ifndef DW_HDMI_AUDIO_H diff --git a/drivers/gpu/drm/eswin/dw_hdmi_cec.c b/drivers/gpu/drm/eswin/dw_hdmi_cec.c index 56553d1d4abd..90e8c973ef06 100644 --- a/drivers/gpu/drm/eswin/dw_hdmi_cec.c +++ b/drivers/gpu/drm/eswin/dw_hdmi_cec.c @@ -20,7 +20,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Authors: Eswin Driver team + * Authors: DengLei */ #include diff --git a/drivers/gpu/drm/eswin/dw_hdmi_cec.h b/drivers/gpu/drm/eswin/dw_hdmi_cec.h index 3ea45a7af644..a43854725d88 100644 --- a/drivers/gpu/drm/eswin/dw_hdmi_cec.h +++ b/drivers/gpu/drm/eswin/dw_hdmi_cec.h @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Authors: Eswin Driver team + * Authors: DengLei */ #ifndef DW_HDMI_CEC_H diff --git a/drivers/gpu/drm/eswin/dw_hdmi_hdcp.c b/drivers/gpu/drm/eswin/dw_hdmi_hdcp.c index 12933da6568b..8147044d12c9 100644 --- a/drivers/gpu/drm/eswin/dw_hdmi_hdcp.c +++ b/drivers/gpu/drm/eswin/dw_hdmi_hdcp.c @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Authors: Eswin Driver team + * Authors: DengLei */ #include #include diff --git a/drivers/gpu/drm/eswin/dw_hdmi_hdcp.h b/drivers/gpu/drm/eswin/dw_hdmi_hdcp.h index 20fd169b387c..8d8c386515f4 100644 --- a/drivers/gpu/drm/eswin/dw_hdmi_hdcp.h +++ b/drivers/gpu/drm/eswin/dw_hdmi_hdcp.h @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Authors: Eswin Driver team + * Authors: DengLei */ #ifndef DW_HDMI_HDCP_H diff --git a/drivers/gpu/drm/eswin/dw_hdmi_hdcp2.c b/drivers/gpu/drm/eswin/dw_hdmi_hdcp2.c index 6c3b0af804f8..aa71bc7cce8e 100644 --- a/drivers/gpu/drm/eswin/dw_hdmi_hdcp2.c +++ b/drivers/gpu/drm/eswin/dw_hdmi_hdcp2.c @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Authors: Eswin Driver team + * Authors: DengLei */ #include #include diff --git a/drivers/gpu/drm/eswin/dw_hdmi_i2s_audio.c b/drivers/gpu/drm/eswin/dw_hdmi_i2s_audio.c index 80229c128eeb..33af4db6fa4c 100644 --- a/drivers/gpu/drm/eswin/dw_hdmi_i2s_audio.c +++ b/drivers/gpu/drm/eswin/dw_hdmi_i2s_audio.c @@ -21,7 +21,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Authors: Eswin Driver team + * Authors: DengLei */ #include diff --git a/drivers/gpu/drm/eswin/es_dc.c b/drivers/gpu/drm/eswin/es_dc.c index daf98bda2105..80538ae9aa9e 100644 --- a/drivers/gpu/drm/eswin/es_dc.c +++ b/drivers/gpu/drm/eswin/es_dc.c @@ -345,6 +345,7 @@ static void es_dc_enable(struct device *dev, struct drm_crtc *crtc) struct es_crtc_state *crtc_state = to_es_crtc_state(crtc->state); struct drm_display_mode *mode = &crtc->state->adjusted_mode; struct dc_hw_display display; + int ret; display.bus_format = crtc_state->output_fmt; display.h_active = mode->hdisplay; @@ -373,7 +374,20 @@ static void es_dc_enable(struct device *dev, struct drm_crtc *crtc) es_dc_clk_configs(dev, true); if (dc->pix_clk_rate != mode->clock) { - clk_set_rate(dc->pix_clk, mode->clock * 1000); + if (mode->clock == 513820) { + ret = clk_set_parent(dc->pix_mux, dc->spll2_fout2); + if (ret < 0) { + dev_err(dev, "failed to set pix mux parent spll2, err:%d\n", ret); + } + /* set mode (2880*1800@90hz) clock to 520M */ + clk_set_rate(dc->pix_clk, 520000000); + } else { + ret = clk_set_parent(dc->pix_mux, dc->vpll_fout1); + if (ret < 0) { + dev_err(dev, "failed to set pix mux parent vpll, err:%d\n", ret); + } + clk_set_rate(dc->pix_clk, mode->clock * 1000); + } dc->pix_clk_rate = mode->clock; } @@ -412,6 +426,10 @@ static bool es_dc_mode_fixup(struct device *dev, struct es_dc *dc = dev_get_drvdata(dev); long clk_rate; + dev_dbg(dev, "adjust mode clock:%d\n", adjusted_mode->clock); + if (adjusted_mode->clock == 513820) + return true; + if (dc->pix_clk) { clk_rate = clk_round_rate(dc->pix_clk, adjusted_mode->clock * 1000); @@ -1083,6 +1101,24 @@ static int dc_probe(struct platform_device *pdev) return PTR_ERR(dc->axi_clk); } + dc->pix_mux = devm_clk_get_optional(dev, "pix_mux"); + if (IS_ERR(dc->pix_mux)) { + dev_err(dev, "failed to get pix mux clk source\n"); + return PTR_ERR(dc->pix_mux); + } + + dc->spll2_fout2 = devm_clk_get_optional(dev, "spll2_fout2"); + if (IS_ERR(dc->spll2_fout2)) { + dev_err(dev, "failed to get spll2 fout2 clk source\n"); + return PTR_ERR(dc->spll2_fout2); + } + + dc->vpll_fout1 = devm_clk_get_optional(dev, "vpll_fout1"); + if (IS_ERR(dc->vpll_fout1)) { + dev_err(dev, "failed to get vpll fout1 clk source\n"); + return PTR_ERR(dc->vpll_fout1); + } + dc->vo_arst = devm_reset_control_get_optional(dev, "vo_arst"); if (IS_ERR_OR_NULL(dc->vo_arst)) { dev_err(dev, "Failed to vo_arst handle\n"); diff --git a/drivers/gpu/drm/eswin/es_dc.h b/drivers/gpu/drm/eswin/es_dc.h index 89b203eebc98..63c5c8d79aa4 100644 --- a/drivers/gpu/drm/eswin/es_dc.h +++ b/drivers/gpu/drm/eswin/es_dc.h @@ -47,6 +47,9 @@ struct es_dc { struct clk *cfg_clk; struct clk *pix_clk; struct clk *axi_clk; + struct clk *pix_mux; + struct clk *spll2_fout2; + struct clk *vpll_fout1; unsigned int pix_clk_rate; /* in KHz */ struct reset_control *vo_arst; diff --git a/drivers/gpu/drm/eswin/es_drv.c b/drivers/gpu/drm/eswin/es_drv.c index 1c588106e39c..d29c3572857c 100644 --- a/drivers/gpu/drm/eswin/es_drv.c +++ b/drivers/gpu/drm/eswin/es_drv.c @@ -25,6 +25,9 @@ #include #include #include +#include +#include +#include #include #include @@ -367,10 +370,16 @@ static int es_drm_of_component_probe(struct device *dev, int i; bool found = false; bool matched = false; + int ret; if (!dev->of_node) return -EINVAL; + ret = of_reserved_mem_device_init(dev); + if (ret) { + dev_info(dev, "No memory-region specified, use system cma, ret:%d\n", ret); + } + /* * Bind the crtc's ports first, so that drm_of_find_possible_crtcs() * called from encoder's .bind callbacks works as expected @@ -465,7 +474,7 @@ static int es_drm_of_component_probe(struct device *dev, compare_of, remote); matched = false; dev_dbg(dev, "matched: %pOF, remote->name:%s\n", - remote, remote->name); + remote, remote->name); } of_node_put(remote); diff --git a/drivers/gpu/drm/eswin/eswin_dw_hdmi.c b/drivers/gpu/drm/eswin/es_dw_hdmi.c similarity index 99% rename from drivers/gpu/drm/eswin/eswin_dw_hdmi.c rename to drivers/gpu/drm/eswin/es_dw_hdmi.c index 19f7cccdca33..84f75833aa62 100644 --- a/drivers/gpu/drm/eswin/eswin_dw_hdmi.c +++ b/drivers/gpu/drm/eswin/es_dw_hdmi.c @@ -16,7 +16,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * - * Authors: Eswin Driver team + * Authors: DengLei */ #include @@ -151,6 +151,14 @@ static const struct dw_hdmi_mpll_config eswin_mpll_cfg[] = { { 0x2648, 0x020f }, }, }, + { + 513820000, + { + { 0x0640, 0x0005 }, + { 0x1658, 0x0019 }, + { 0x2648, 0x000f }, + }, + }, { 594000000, { @@ -195,6 +203,10 @@ static const struct dw_hdmi_curr_ctrl eswin_cur_ctr[] = { 297000000, { 0x3041, 0x3182, 0x3100 }, }, + { + 513820000, + { 0x3080, 0x31c0, 0x3100 }, + }, { 594000000, { 0x3080, 0x31c0, 0x3100 }, @@ -209,7 +221,7 @@ static struct dw_hdmi_phy_config eswin_phy_config[] = { /*pixelclk symbol term vlev*/ { 165000000, 0x8088, 0x0007, 0x0180 }, { 297000000, 0x80c8, 0x0004, 0x0180 }, - { 594000000, 0x80f8, 0x0000, 0x0180 }, + { 594000000, 0x80f3, 0x0000, 0x0180 }, { ~0UL, 0x0000, 0x0000, 0x0000 } }; diff --git a/drivers/interconnect/eswin/noc.c b/drivers/interconnect/eswin/noc.c index 2bcbe3f48f59..cc232396f842 100644 --- a/drivers/interconnect/eswin/noc.c +++ b/drivers/interconnect/eswin/noc.c @@ -515,7 +515,7 @@ static int win2030_noc_get_error(struct win2030_noc_device *noc_device) struct win2030_noc_error *noc_err; unsigned long flags; int i; - char buf[1024] = {'\0'}; + char buf[2048] = {'\0'}; struct device *mydev = noc_device->dev; diff --git a/drivers/memory/eswin/Kconfig b/drivers/memory/eswin/Kconfig index 3078936326e4..c187f1c0ac0a 100644 --- a/drivers/memory/eswin/Kconfig +++ b/drivers/memory/eswin/Kconfig @@ -31,5 +31,6 @@ source "drivers/memory/eswin/es_rsvmem_heap/Kconfig" source "drivers/memory/eswin/es_mmz_vb/Kconfig" source "drivers/memory/eswin/es_dev_buf/Kconfig" source "drivers/memory/eswin/es_iommu_rsv/Kconfig" +source "drivers/memory/eswin/es_dma_memcp/Kconfig" endif diff --git a/drivers/memory/eswin/Makefile b/drivers/memory/eswin/Makefile index c07fadc64d44..e6e57575ccb8 100644 --- a/drivers/memory/eswin/Makefile +++ b/drivers/memory/eswin/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_ESWIN_RSVMEM_HEAP) += es_rsvmem_heap/ obj-$(CONFIG_ESWIN_RSVMEM_HEAP) += es_mmz_vb/ obj-$(CONFIG_ESWIN_DEV_DMA_BUF) += es_dev_buf/ obj-$(CONFIG_ESWIN_IOMMU_RSV) += es_iommu_rsv/ +obj-$(CONFIG_ESWIN_DMA_MEMCP) += es_dma_memcp/ ES_MEM_HEADER := drivers/memory/eswin/ diff --git a/drivers/memory/eswin/codacache/llc_spram.c b/drivers/memory/eswin/codacache/llc_spram.c index ed71d83c3060..8ef878c0abef 100644 --- a/drivers/memory/eswin/codacache/llc_spram.c +++ b/drivers/memory/eswin/codacache/llc_spram.c @@ -42,6 +42,7 @@ #include #include +#include #include "llc_spram.h" #define HAVE_LLC_HARDWARE 1 @@ -102,6 +103,8 @@ struct spram_dev { struct reset_control *rstc_cfg; struct reset_control *rstc_core; struct reset_control *rstc_llc; + struct regulator *npu_regulator; + u8 is_low_freq; }; #define dma_buf_map iosys_map @@ -671,9 +674,8 @@ static int llc_clk_init(struct platform_device *pdev) return 0; } -static int llc_clk_enable(struct platform_device *pdev) +static int llc_clk_enable(struct spram_dev *spram) { - struct spram_dev *spram = platform_get_drvdata(pdev); int ret = 0; if (spram == NULL) @@ -682,29 +684,41 @@ static int llc_clk_enable(struct platform_device *pdev) /*enable clk*/ ret = clk_prepare_enable(spram->aclk); if (ret) { - dev_err(&pdev->dev, "failed to enable aclk: %d\n", ret); + dev_err(spram->dev, "failed to enable aclk: %d\n", ret); return ret; } ret = clk_prepare_enable(spram->cfg_clk); if (ret) { - dev_err(&pdev->dev, "failed to enable cfg_clk: %d\n", ret); + dev_err(spram->dev, "failed to enable cfg_clk: %d\n", ret); return ret; } ret = clk_prepare_enable(spram->llc_clk); if (ret) { - dev_err(&pdev->dev, "failed to enable llc_clk: %d\n", ret); + dev_err(spram->dev, "failed to enable llc_clk: %d\n", ret); return ret; } ret = clk_prepare_enable(spram->core_clk); if (ret) { - dev_err(&pdev->dev, "failed to enable core_clk: %d\n", ret); + dev_err(spram->dev, "failed to enable core_clk: %d\n", ret); return ret; } return 0; } +static int llc_clk_disable(struct spram_dev *spram) +{ + if (spram == NULL) + return -EINVAL; + clk_disable_unprepare(spram->aclk); + clk_disable_unprepare(spram->cfg_clk); + clk_disable_unprepare(spram->llc_clk); + clk_disable_unprepare(spram->core_clk); + + return 0; +} + static int llc_rst_init(struct platform_device *pdev) { struct spram_dev *spram = platform_get_drvdata(pdev); @@ -739,56 +753,42 @@ static int llc_rst_init(struct platform_device *pdev) return 0; } -static int llc_clk_set_parent(struct platform_device *pdev, u8 *is_low_freq) +static int llc_clk_set_parent(struct platform_device *pdev) { int ret; struct spram_dev *spram = platform_get_drvdata(pdev); - struct device_node *np; - struct regulator *npu_regulator; struct device *dev = &pdev->dev; + spram->is_low_freq = 0; if (spram == NULL) return -EINVAL; np = of_node_get(dev->of_node); - npu_regulator = devm_regulator_get_exclusive(dev, "npu"); - - if ((NULL == npu_regulator) || (IS_ERR(npu_regulator))) + spram->npu_regulator = devm_regulator_get(dev, "npu"); + ret = regulator_get_voltage(spram->npu_regulator); + if (ret < 0) { dev_warn(dev, "failed to get npu regulator,the npu freq will set to 1G\n"); - *is_low_freq = 1; - //return -ENODEV; + spram->is_low_freq = 1; } else { - *is_low_freq = (of_property_read_bool(np, "apply_npu_1G_freq")); + spram->is_low_freq = (of_property_read_bool(np, "apply_npu_1G_freq")); dev_dbg(dev, "success to get npu regulator,apply_npu_1G_freq:%d\n", - *is_low_freq); - } - - if (0 == *is_low_freq) - { - ret = regulator_set_voltage(npu_regulator, NPU_1P5G_VOLTAGE, NPU_1P5G_VOLTAGE); - dev_dbg(dev,"name:%s,volt:%d,ret:%d\n",pdev->name,NPU_1P5G_VOLTAGE,ret); - if(0 != ret) + spram->is_low_freq); + ret = regulator_enable(spram->npu_regulator); + if (ret < 0) { - dev_err(dev, "set volt:%duV ret:%d\n", NPU_1P5G_VOLTAGE,ret); - return -EINVAL; + return ret; } - /* devm_regulator_put(npu_regulator); */ - mdelay(10); + } + if (0 == spram->is_low_freq) + { ret = clk_set_parent(spram->mux_u_npu_core_3mux1_gfree, spram->fixed_rate_clk_spll1_fout1); } else { - if (((NULL != npu_regulator)) && (!IS_ERR(npu_regulator))) - { - regulator_set_voltage(npu_regulator, NPU_DEFAULT_VOLTAGE, NPU_DEFAULT_VOLTAGE); - dev_dbg(dev,"name:%s,volt:%d,ret:%d\n", pdev->name,NPU_DEFAULT_VOLTAGE,ret); - /* devm_regulator_put(npu_regulator); */ - mdelay(10); - } ret = clk_set_parent(spram->mux_u_npu_core_3mux1_gfree, spram->fixed_rate_clk_spll2_fout2); } @@ -798,10 +798,9 @@ static int llc_clk_set_parent(struct platform_device *pdev, u8 *is_low_freq) ret); return ret; } - return 0; } -static int llc_clk_set_frq(struct platform_device *pdev, u8 is_low_freq) +static int llc_clk_set_frq(struct platform_device *pdev) { int ret; unsigned long rate = 0; @@ -818,7 +817,7 @@ static int llc_clk_set_frq(struct platform_device *pdev, u8 is_low_freq) return ret; } - if (0 == is_low_freq) + if (0 == spram->is_low_freq) { rate = clk_round_rate(spram->llc_clk, NPU_LLC_CLK_1P5G_RATE); ret = clk_set_rate(spram->llc_clk, rate); @@ -858,10 +857,9 @@ static int llc_clk_set_frq(struct platform_device *pdev, u8 is_low_freq) return 0; } -static int llc_rst_deassert(struct platform_device *pdev) +static int llc_rst_deassert(struct spram_dev *spram) { int ret = 0; - struct spram_dev *spram = platform_get_drvdata(pdev); if (spram == NULL) return -EINVAL; @@ -885,6 +883,25 @@ static int llc_rst_deassert(struct platform_device *pdev) return 0; } + +static int llc_rst_assert(struct spram_dev *spram) +{ + int ret = 0; + + if (spram == NULL) + return -EINVAL; + ret = reset_control_assert(spram->rstc_axi); + WARN_ON(0 != ret); + ret = reset_control_assert(spram->rstc_core); + WARN_ON(0 != ret); + ret = reset_control_assert(spram->rstc_llc); + WARN_ON(0 != ret); + ret = reset_control_assert(spram->rstc_cfg); + WARN_ON(0 != ret); + + return 0; +} + static int llc_clk_rst_print(struct platform_device *pdev) { uint32_t regval[5]; @@ -944,8 +961,9 @@ static int llc_clk_rst_print(struct platform_device *pdev) static int llc_clk_rst_init(struct platform_device *pdev) { int ret = 0; - u8 is_low_freq = 0; + struct spram_dev *spram = platform_get_drvdata(pdev); + spram->is_low_freq = 0; dev_dbg(&pdev->dev, "---%s\n", __func__); ret = llc_clk_init(pdev); @@ -954,7 +972,7 @@ static int llc_clk_rst_init(struct platform_device *pdev) return ret; } - ret = llc_clk_set_parent(pdev, &is_low_freq); + ret = llc_clk_set_parent(pdev); if(ret != 0){ dev_err(&pdev->dev, "llc_clk_set_parent error: %d\n", ret); return ret; @@ -966,19 +984,19 @@ static int llc_clk_rst_init(struct platform_device *pdev) return ret; } - ret = llc_clk_set_frq(pdev, is_low_freq); + ret = llc_clk_set_frq(pdev); if(ret != 0){ dev_err(&pdev->dev, "llc_clk_set_frq error: %d\n", ret); return ret; } - ret = llc_clk_enable(pdev); + ret = llc_clk_enable(spram); if(ret != 0){ dev_err(&pdev->dev, "llc_clk_enable error: %d\n", ret); return ret; } - llc_rst_deassert(pdev); + llc_rst_deassert(spram); llc_clk_rst_print(pdev); dev_dbg(&pdev->dev, "%s done successfully!\n", __func__); @@ -1438,6 +1456,101 @@ static int spram_contiguous_alloc(struct spram_dev *spram, size_t len, struct sg } #endif +#ifdef CONFIG_PM +static int __maybe_unused llc_suspend(struct device *dev) +{ + + struct spram_dev *spram = dev_get_drvdata(dev); + + llc_rst_assert(spram); + if (!pm_runtime_status_suspended(dev)) + { + llc_clk_disable(spram); + } + if ((NULL != spram->npu_regulator) && (!IS_ERR(spram->npu_regulator))) + { + regulator_disable(spram->npu_regulator); + } + + return 0; +} + +static int __maybe_unused llc_resume(struct device *dev) +{ + int ret = 0; + int is_enable = 0; + struct spram_dev *spram = dev_get_drvdata(dev); + + if ((NULL != spram->npu_regulator) && (!IS_ERR(spram->npu_regulator))) + { + is_enable = regulator_is_enabled(spram->npu_regulator); + if(0 == is_enable) + { + mdelay(20); + } + ret = regulator_enable(spram->npu_regulator); + if (ret < 0) + { + dev_err(spram->dev, "regulator_enable error: %d\n", ret); + return ret; + } + if(0 == is_enable) + { + mdelay(20); + } + } + + ret = llc_clk_enable(spram); + if(ret != 0){ + dev_err(spram->dev, "llc_clk_enable error: %d\n", ret); + return ret; + } + ret = llc_rst_deassert(spram); + if (ret) + return ret; + + ret = llc_spram_init(spram); + if (ret) { + return ret; + } + + return ret; +} + + +static int __maybe_unused llc_runtime_suspend(struct device *dev) +{ + struct spram_dev *spram = dev_get_drvdata(dev); + + llc_clk_disable(spram); + + return 0; +} + +static int __maybe_unused llc_runtime_resume(struct device *dev) +{ + struct spram_dev *spram = dev_get_drvdata(dev); + int ret = 0; + + ret = llc_clk_enable(spram); + if(ret != 0){ + dev_err(spram->dev, "llc_clk_enable error: %d\n", ret); + } + + return ret; +} + +static const struct dev_pm_ops llc_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(llc_suspend, llc_resume) + SET_RUNTIME_PM_OPS(llc_runtime_suspend, + llc_runtime_resume, NULL) +}; + +#define DEV_PM_OPS (&llc_dev_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM */ + static struct dma_buf *spram_heap_allocate(struct dma_heap *heap, unsigned long len, unsigned long fd_flags, @@ -1555,6 +1668,51 @@ static int __add_spram_heap(struct spram_dev *spram, void *data) return 0; } +static ssize_t npu_regulator_show(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct spram_dev *spram = dev_get_drvdata(device); + + return sprintf(buf, "%d\n",regulator_is_enabled(spram->npu_regulator)); + +} + +static ssize_t npu_regulator_store(struct device *device, + struct device_attribute *attr, const char *buf, + size_t count) +{ + int ret = 0; + struct spram_dev *spram = dev_get_drvdata(device); + + if (!strncmp(buf, "0", 1)) + { + regulator_disable(spram->npu_regulator); + } + else + { + ret = regulator_enable(spram->npu_regulator); + if (ret < 0) + { + return ret; + } + + } + + return count; +} + +static DEVICE_ATTR_RW(npu_regulator); + +static struct attribute *llc_attrs[] = { + &dev_attr_npu_regulator.attr, + NULL, +}; + +static struct attribute_group llc_attr_group = { + .name = NULL, /* we want them in the same directory */ + .attrs = llc_attrs, +}; + static int llc_probe(struct platform_device *pdev) { struct spram_dev *spram; @@ -1651,7 +1809,9 @@ static int llc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "%s Done!\n", __func__); pdevs[spram->nid] = pdev; - + ret = sysfs_create_group(&pdev->dev.kobj, &llc_attr_group); + if (ret) + dev_err(&pdev->dev, "failed to create sysfs group: %d\n", ret); return 0; } @@ -1666,6 +1826,7 @@ static struct platform_driver llc_driver = { .driver = { .name = DEVICE_NAME, .of_match_table = llc_dt_ids, + .pm = DEV_PM_OPS, }, .probe = llc_probe, }; @@ -1674,3 +1835,4 @@ builtin_platform_driver(llc_driver); MODULE_DESCRIPTION("ESWIN LLC driver"); MODULE_AUTHOR("Lin MIn "); MODULE_LICENSE("GPL"); + diff --git a/drivers/memory/eswin/es_dma_memcp/Kconfig b/drivers/memory/eswin/es_dma_memcp/Kconfig new file mode 100644 index 000000000000..deff4abf37de --- /dev/null +++ b/drivers/memory/eswin/es_dma_memcp/Kconfig @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 + +config ESWIN_DMA_MEMCP + tristate "ESWIN DMA memory copy" + help + ESWIN DMA memory copy device. diff --git a/drivers/memory/eswin/es_dma_memcp/Makefile b/drivers/memory/eswin/es_dma_memcp/Makefile new file mode 100644 index 000000000000..615375e6b476 --- /dev/null +++ b/drivers/memory/eswin/es_dma_memcp/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ESWIN_DMA_MEMCP) += es_dma_memcp.o diff --git a/drivers/memory/eswin/es_dma_memcp/es_dma_memcp.c b/drivers/memory/eswin/es_dma_memcp/es_dma_memcp.c new file mode 100644 index 000000000000..7d0772bf03cd --- /dev/null +++ b/drivers/memory/eswin/es_dma_memcp/es_dma_memcp.c @@ -0,0 +1,604 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ESWIN DMA MEMCP Driver + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: Zonglin Geng + * Yuyang Cong + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "es_memcp" + +#define MAX_NUM_USED_DMA_CH (4) + +static struct device *esw_memcp_dev; + +struct esw_memcp_dma_buf_info { + struct dma_buf *dma_buf; + int mem_nid; + struct dma_buf_attachment *attach; + struct sg_table *sgt; +}; + +struct cmdq { + struct workqueue_struct *wq; + struct mutex lock; + atomic_t total_tasks; + atomic_t completed_tasks; +}; + +struct esw_cmdq_task { + struct cmdq *cmdq; + struct esw_memcp_f2f_cmd f2f_cmd; + struct esw_memcp_dma_buf_info src_buf; + struct esw_memcp_dma_buf_info dst_buf; + struct work_struct work; + struct dma_chan *dma_ch; /* pointer to the dma channel. */ + struct completion dma_finished; +}; + +#ifdef CONFIG_NUMA +static int memcp_attach_dma_buf(struct device *dma_dev, struct esw_memcp_dma_buf_info *buf_info); +static int memcp_detach_dma_buf(struct dma_buf_attachment *attach, struct sg_table *sgt); +#define PAGE_IN_SPRAM_DIE0(page) ((page_to_phys(page)>=0x59000000) && (page_to_phys(page)<0x59400000)) +#define PAGE_IN_SPRAM_DIE1(page) ((page_to_phys(page)>=0x79000000) && (page_to_phys(page)<0x79400000)) +static int esw_memcp_get_mem_nid(struct esw_memcp_dma_buf_info *buf_info) +{ + int ret = 0; + struct page *page = NULL; + int nid = -1; + + ret = memcp_attach_dma_buf(esw_memcp_dev, buf_info); + if(ret) { + pr_err("Failed to attach DMA buffer, ret=%d\n", ret); + return ret; + } + + page = sg_page(buf_info->sgt->sgl); + if (unlikely(PAGE_IN_SPRAM_DIE0(page))) { + nid = 0; + } + else if(unlikely(PAGE_IN_SPRAM_DIE1(page))) { + nid = 1; + } + else { + nid = page_to_nid(page); + } + + ret = memcp_detach_dma_buf(buf_info->attach, buf_info->sgt); + if(ret) { + pr_err("Failed to detach DMA buffer, , ret=%d\n", ret); + return ret; + } + + buf_info->mem_nid = nid; + + return ret; +} +#else +static int esw_memcp_get_mem_nid(struct esw_memcp_dma_buf_info *buf_info) +{ + buf_info->mem_nid = 0; + return 0; +} +#endif + +static bool filter(struct dma_chan *chan, void *param) +{ +#ifdef CONFIG_NUMA + if((*(int *)param) == 2) + return true; + else + return (*(int *)param) == dev_to_node(chan->device->dev); +#else + return true; +#endif +} + + +int esw_memcp_alloc_dma(struct esw_cmdq_task *task) +{ + int ret = 0; + dma_cap_mask_t mask; + struct dma_chan *dma_ch = NULL; + + ret = esw_memcp_get_mem_nid(&task->src_buf); + if(ret) { + return ret; + } + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + + dma_ch = dma_request_channel(mask, filter, &task->src_buf.mem_nid); + if (IS_ERR(dma_ch)) { + pr_warn("dma request channel failed, Try using any of them.\n"); + dma_ch = dma_request_channel(mask, NULL, NULL); + } + + if (IS_ERR(dma_ch)) { + pr_err("dma request channel failed\n"); + return -ENODEV; + } + + task->dma_ch = dma_ch; + return 0; +} + +static int memcp_attach_dma_buf(struct device *dma_dev, struct esw_memcp_dma_buf_info *buf_info) +{ + int ret = 0; + struct dma_buf *dma_buf; + struct dma_buf_attachment *attach; + struct sg_table *sgt; + + if (!buf_info || !dma_dev) { + pr_err("Invalid parameters: buf_info or dma_dev is NULL\n"); + return -EINVAL; + } + + dma_buf = buf_info->dma_buf; + if (IS_ERR(dma_buf)) { + return PTR_ERR(dma_buf); + } + /* Ref + 1 */ + attach = dma_buf_attach(dma_buf, dma_dev); + if (IS_ERR(attach)) { + ret = PTR_ERR(attach); + return ret; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0) + sgt = dma_buf_map_attachment_unlocked(attach, DMA_BIDIRECTIONAL); +#else + sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); +#endif + if (IS_ERR(sgt)) { + ret = PTR_ERR(sgt); + dma_buf_detach(dma_buf, attach); + return ret; + } +#ifdef DMA_MEMCP_DEBUG_EN + struct scatterlist *sg = NULL; + u64 addr; + int len; + int i = 0; + for_each_sgtable_dma_sg(sgt, sg, i) { + addr = sg_dma_address(sg); + len = sg_dma_len(sg); + } +#endif + + buf_info->attach = attach; + buf_info->sgt = sgt; + return ret; +} + +static int memcp_detach_dma_buf(struct dma_buf_attachment *attach, struct sg_table *sgt) +{ + int ret = 0; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 6, 0) + dma_buf_unmap_attachment_unlocked(attach, sgt, DMA_BIDIRECTIONAL); +#else + dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); +#endif + /* detach attach->dma_buf*/ + dma_buf_detach(attach->dmabuf, attach); + return ret; +} + +static int memcp_detach_dma_buf_check(struct esw_memcp_dma_buf_info *buf_info) +{ + int ret = 0; + if(buf_info->attach) { + ret = memcp_detach_dma_buf(buf_info->attach, buf_info->sgt); + buf_info->attach = NULL; + } + return ret; +} + +static int esw_memcp_release_cmdq_task(struct esw_cmdq_task *cmdq_task) +{ + memcp_detach_dma_buf_check(&cmdq_task->src_buf); + memcp_detach_dma_buf_check(&cmdq_task->dst_buf); + + if (cmdq_task->src_buf.dma_buf) { + dma_buf_put(cmdq_task->src_buf.dma_buf); + cmdq_task->src_buf.dma_buf = NULL; + } + if (cmdq_task->dst_buf.dma_buf) { + dma_buf_put(cmdq_task->dst_buf.dma_buf); + cmdq_task->dst_buf.dma_buf = NULL; + } + + if (cmdq_task->dma_ch) { + dma_release_channel(cmdq_task->dma_ch); + cmdq_task->dma_ch = NULL; + } + + kfree(cmdq_task); + return 0; +} + + +static void esw_memcp_complete_func(void *cb_param) +{ + struct esw_cmdq_task *cmdq_task = (struct esw_cmdq_task *)cb_param; + + complete(&cmdq_task->dma_finished); +} + +static int esw_memcp_start_dma_f2f_trans(struct esw_cmdq_task *cmdq_task) +{ + int ret = 0; + struct esw_memcp_f2f_cmd *f2f_cmd; + struct dma_buf_attachment *attach; + struct sg_table *sgt; + struct dma_buf *dma_buf; + struct dma_chan *dma_ch; + struct device *dma_dev; + enum dma_ctrl_flags flags; + dma_cookie_t cookie; //used for judge whether trans has been completed. + struct dma_async_tx_descriptor *tx = NULL; + dma_addr_t src_buf_addr, dst_buf_addr; + size_t src_size, dst_size; + + ret = esw_memcp_alloc_dma(cmdq_task); + if(ret) { + goto release_cmdq_task; + } + + f2f_cmd = &cmdq_task->f2f_cmd; + dma_ch = cmdq_task->dma_ch; + dma_dev = dmaengine_get_dma_device(dma_ch); + + ret = memcp_attach_dma_buf(dma_dev, &cmdq_task->src_buf); + if(ret) { + goto release_cmdq_task; + } + attach = cmdq_task->src_buf.attach; + sgt = cmdq_task->src_buf.sgt; + src_buf_addr = sg_dma_address(sgt->sgl) + f2f_cmd->src_offset; + dma_buf = attach->dmabuf; + src_size = dma_buf->size; + + ret = memcp_attach_dma_buf(dma_dev, &cmdq_task->dst_buf); + if(ret) { + goto release_cmdq_task; + } + attach = cmdq_task->dst_buf.attach; + sgt = cmdq_task->dst_buf.sgt; + dst_buf_addr = sg_dma_address(sgt->sgl) + f2f_cmd->dst_offset; + dma_buf = attach->dmabuf; + dst_size = dma_buf->size; + + init_completion(&cmdq_task->dma_finished); + dma_ch = cmdq_task->dma_ch; + flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT; + tx = dmaengine_prep_dma_memcpy(dma_ch, dst_buf_addr, src_buf_addr, f2f_cmd->len, flags); + if(!tx){ + pr_err("Failed to prepare DMA memcp\n"); + ret = -EFAULT; + goto release_cmdq_task; + } + + tx->callback = esw_memcp_complete_func; + tx->callback_param = cmdq_task; + + cookie = dmaengine_submit(tx); + if(dma_submit_error(cookie)){ + pr_err("Failed to dma tx_submit\n"); + ret = -EFAULT; + goto release_cmdq_task; + } + + dma_async_issue_pending(dma_ch); + if (wait_for_completion_interruptible_timeout(&cmdq_task->dma_finished, + msecs_to_jiffies(cmdq_task->f2f_cmd.timeout)) == 0) { + pr_err("DMA transfer timeout.\n"); + ret = -ETIMEDOUT; + dmaengine_terminate_sync(dma_ch); + goto release_cmdq_task; + } + +release_cmdq_task: + esw_memcp_release_cmdq_task(cmdq_task); + return ret; +} + + +static void cmdq_task_worker(struct work_struct *work) { + struct esw_cmdq_task *task = container_of(work, struct esw_cmdq_task, work); + struct cmdq *q = task->cmdq; + int ret; + + if (!task) { + pr_err("cmdq_task_worker: Invalid task pointer\n"); + return; + } + + // Start DMA Transfer + ret = esw_memcp_start_dma_f2f_trans(task); + + if (ret) { + pr_err("cmdq_task_worker: DMA transfer failed with error code %d\n", ret); + } + atomic_inc(&q->completed_tasks); + +} + +static int esw_cmdq_add_task(struct file *filp, void __user *user_arg) { + struct cmdq *q = (struct cmdq *)filp->private_data; + struct esw_cmdq_task *cmdq_task; + struct esw_memcp_f2f_cmd memcp_f2f_cmd; + int ret; + + if (!q || !q->wq) { + pr_err("CMDQ or workqueue is NULL\n"); + return -EINVAL; + } + + cmdq_task = kzalloc(sizeof(struct esw_cmdq_task), GFP_KERNEL); + if (!cmdq_task) { + pr_err("Failed to allocate cmdq_task\n"); + return -ENOMEM; + } + + if (copy_from_user(&memcp_f2f_cmd, user_arg, sizeof(struct esw_memcp_f2f_cmd))) { + pr_err("Failed to copy data from user space\n"); + kfree(cmdq_task); + return -EFAULT; + } + + cmdq_task->cmdq = q; + cmdq_task->f2f_cmd = memcp_f2f_cmd; + + cmdq_task->src_buf.dma_buf = dma_buf_get(memcp_f2f_cmd.src_fd); + if (IS_ERR(cmdq_task->src_buf.dma_buf)) { + pr_err("Failed to get src dma_buf, src_fd=%d, err=%ld\n", + memcp_f2f_cmd.src_fd, PTR_ERR(cmdq_task->src_buf.dma_buf)); + kfree(cmdq_task); + return PTR_ERR(cmdq_task->src_buf.dma_buf); + } + + if ((memcp_f2f_cmd.src_offset + memcp_f2f_cmd.len) > cmdq_task->src_buf.dma_buf->size) { + pr_err("Source buffer overflow: src_offset=%d, len=%lu, buf_size=%lu\n", + memcp_f2f_cmd.src_offset, memcp_f2f_cmd.len, cmdq_task->src_buf.dma_buf->size); + dma_buf_put(cmdq_task->src_buf.dma_buf); + kfree(cmdq_task); + return -EINVAL; + } + + cmdq_task->dst_buf.dma_buf = dma_buf_get(memcp_f2f_cmd.dst_fd); + if (IS_ERR(cmdq_task->dst_buf.dma_buf)) { + pr_err("Failed to get dst dma_buf, dst_fd=%d, err=%ld\n", + memcp_f2f_cmd.dst_fd, PTR_ERR(cmdq_task->dst_buf.dma_buf)); + dma_buf_put(cmdq_task->src_buf.dma_buf); + kfree(cmdq_task); + return PTR_ERR(cmdq_task->dst_buf.dma_buf); + } + + if ((memcp_f2f_cmd.dst_offset + memcp_f2f_cmd.len) > cmdq_task->dst_buf.dma_buf->size) { + pr_err("Destination buffer overflow: dst_offset=%d, len=%lu, buf_size=%lu\n", + memcp_f2f_cmd.dst_offset, memcp_f2f_cmd.len, cmdq_task->dst_buf.dma_buf->size); + dma_buf_put(cmdq_task->src_buf.dma_buf); + dma_buf_put(cmdq_task->dst_buf.dma_buf); + kfree(cmdq_task); + return -EINVAL; + } + + INIT_WORK(&cmdq_task->work, cmdq_task_worker); + ret = queue_work(cmdq_task->cmdq->wq, &cmdq_task->work); + if (!ret) { + pr_err("Failed to queue work\n"); + dma_buf_put(cmdq_task->src_buf.dma_buf); + dma_buf_put(cmdq_task->dst_buf.dma_buf); + kfree(cmdq_task); + return -EFAULT; + } + + atomic_inc(&q->total_tasks); + + return 0; +} + +static int esw_cmdq_sync(struct file *filp) { + struct cmdq *q = (struct cmdq *)filp->private_data; + + if (!q) { + pr_err("esw_cmdq_sync: Invalid cmdq\n"); + return -EINVAL; + } + + flush_workqueue(q->wq); + + return 0; +} + + + +static int esw_cmdq_query(struct file *file, void __user *user_arg) +{ + struct cmdq *q; + struct esw_cmdq_query query; + + if (!file || !user_arg) { + pr_err("esw_cmdq_query: Invalid arguments\n"); + return -EINVAL; + } + + q = file->private_data; + if (!q) { + pr_err("esw_cmdq_query: No cmdq associated with this file descriptor\n"); + return -EINVAL; + } + + int total = atomic_read(&q->total_tasks); + int completed = atomic_read(&q->completed_tasks); + + query.status = (total == completed) ? 0 : 1; // 0 FREE,1 BUSY + query.task_count = total - completed; + + if (copy_to_user(user_arg, &query, sizeof(query))) { + pr_err("esw_cmdq_query: Failed to copy data to user space\n"); + return -EFAULT; + } + + return 0; +} + +static long esw_memcp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + + switch (cmd) { + case (ESW_CMDQ_ADD_TASK): + ret = esw_cmdq_add_task(filp, (void *)arg); + break; + + case (ESW_CMDQ_SYNC): + ret = esw_cmdq_sync(filp); + break; + + case (ESW_CMDQ_QUERY): + ret = esw_cmdq_query(filp, (void *)arg); + break; + + default: + dev_err(esw_memcp_dev, "invalid cmd! cmd=0x%x, arg=0x%lx\n", cmd, arg); + ret = -EINVAL; + break; + } + + return ret; +} + +static ssize_t esw_memcp_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) +{ + dev_info(esw_memcp_dev, "Write: operation not supported\n"); + return -EINVAL; +} + +static int esw_memcp_open(struct inode *inode, struct file *filp) +{ + struct cmdq *q; + + q = kzalloc(sizeof(struct cmdq), GFP_KERNEL); + if (!q) { + pr_err("Failed to allocate cmdq\n"); + return -ENOMEM; + } + + q->wq = alloc_workqueue("cmdq_wq", WQ_UNBOUND | WQ_FREEZABLE | WQ_MEM_RECLAIM, 0); + if (!q->wq) { + pr_err("Failed to allocate workqueue\n"); + kfree(q); + return -ENOMEM; + } + + atomic_set(&q->total_tasks, 0); + atomic_set(&q->completed_tasks, 0); + + filp->private_data = q; + + return 0; +} + + + +static int esw_memcp_release(struct inode *inode, struct file *filp) +{ + struct cmdq *q = (struct cmdq *)filp->private_data; + + if (q) { + if (q->wq) { + destroy_workqueue(q->wq); + } + + kfree(q); + } + + return 0; +} + + +static struct file_operations esw_memcp_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = esw_memcp_write, + .unlocked_ioctl = esw_memcp_ioctl, + .open = esw_memcp_open, + .release = esw_memcp_release, +}; + +static struct miscdevice esw_memcp_miscdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = DRIVER_NAME, + .mode = 0666, + .fops = &esw_memcp_fops, +}; + +static int __init esw_memcp_init(void) +{ + int ret = 0; + + ret = misc_register(&esw_memcp_miscdev); + if (ret) { + pr_err("%s: Failed to register misc device, err=%d\n", __func__, ret); + return ret; + } + + esw_memcp_dev = esw_memcp_miscdev.this_device; + + if (!esw_memcp_dev->dma_mask) { + esw_memcp_dev->dma_mask = &esw_memcp_dev->coherent_dma_mask; + } + ret = dma_set_mask_and_coherent(esw_memcp_dev, DMA_BIT_MASK(64)); + if (ret) + dev_err(esw_memcp_dev, "Failed to set coherent mask.\n"); + return ret; +} + +static void __exit esw_memcp_exit(void) +{ + misc_deregister(&esw_memcp_miscdev); +} +module_init(esw_memcp_init); +module_exit(esw_memcp_exit); + +MODULE_AUTHOR("Geng Zonglin "); +MODULE_AUTHOR("Yuyang Cong "); +MODULE_DESCRIPTION("ESW DMA MEMCP Driver"); +MODULE_LICENSE("GPL v2"); \ No newline at end of file diff --git a/drivers/memory/eswin/es_rsvmem_heap/dmabuf-heap-import-helper.c b/drivers/memory/eswin/es_rsvmem_heap/dmabuf-heap-import-helper.c index d9ba68d918ef..283fbdfb1c07 100644 --- a/drivers/memory/eswin/es_rsvmem_heap/dmabuf-heap-import-helper.c +++ b/drivers/memory/eswin/es_rsvmem_heap/dmabuf-heap-import-helper.c @@ -1169,3 +1169,190 @@ static void __exit split_dmabuf_exit(void) module_init(split_dmabuf_init); module_exit(split_dmabuf_exit); + + +static int vmf_replace_pages(struct vm_area_struct *vma, unsigned long addr, + struct page **pages, unsigned long num, pgprot_t prot) +{ + struct mm_struct *const mm = vma->vm_mm; + unsigned long remaining_pages_total = num; + unsigned long pfn; + pte_t *pte, entry; + spinlock_t *ptl; + unsigned long newprot_val = pgprot_val(prot); + pgprot_t new_prot; + u32 i = 0; + + while (remaining_pages_total) { + pte = get_locked_pte(mm, addr, &ptl); + if (!pte) + return VM_FAULT_OOM; + + entry = ptep_get(pte); + pfn = page_to_pfn(pages[i]); + pr_debug("page_to_pfn(pages[%d])=0x%lx, pte_pfn(entry)=0x%lx, pte_val(entry)=0x%lx\n", + i, pfn, pte_pfn(entry), pte_val(entry)); + + newprot_val = (pte_val(entry) & (~_PAGE_PFN_MASK)) | newprot_val; + if (newprot_val == (pte_val(entry) & (~_PAGE_PFN_MASK))) + goto SKIP_PAGE; + + new_prot = __pgprot(newprot_val); + entry = mk_pte(pages[i], new_prot); + pr_debug("page_to_pfn(pages[%d])=0x%lx, pte_pfn(entry)=0x%lx, modified pte_val(entry)=0x%lx\n", + i, page_to_pfn(pages[i]), pte_pfn(entry), pte_val(entry)); + set_pte_at(vma->vm_mm, addr, pte, entry); + update_mmu_cache(vma, addr, pte); + +SKIP_PAGE: + addr += PAGE_SIZE; + pte_unmap_unlock(pte, ptl); + remaining_pages_total--; + i++; + } + + return 0; +} + +static int zap_and_replace_pages(struct vm_area_struct *vma, u64 addr, size_t len, pgprot_t prot) +{ + struct page **pages; + u32 offset; + unsigned long nr_pages; + u64 first, last; + u64 addr_aligned = ALIGN_DOWN(addr, PAGE_SIZE); + u32 i; + int ret = -ENOMEM; + + if (!len) { + pr_err("invalid userptr size.\n"); + return -EINVAL; + } + /* offset into first page */ + offset = offset_in_page(addr); + + /* Calculate number of pages */ + first = (addr & PAGE_MASK) >> PAGE_SHIFT; + last = ((addr + len - 1) & PAGE_MASK) >> PAGE_SHIFT; + nr_pages = last - first + 1; + pr_debug("%s:%d, addr=0x%llx(addr_aligned=0x%llx), len=0x%lx, nr_pages=0x%lx(fist:0x%llx,last:0x%llx)\n", + __func__, __LINE__, addr, addr_aligned, len, nr_pages, first, last); + + /* alloc array to storing the pages */ + pages = kvmalloc_array(nr_pages, + sizeof(struct page *), + GFP_KERNEL); + if (!pages) + return -ENOMEM; + + ret = get_user_pages_fast(addr_aligned, + nr_pages, + FOLL_FORCE | FOLL_WRITE, + pages); + + if (ret != nr_pages) { + nr_pages = (ret >= 0) ? ret : 0; + pr_err("get_user_pages_fast, err=%d [0x%lx]\n", + ret, nr_pages); + ret = ret < 0 ? ret : -EINVAL; + goto free_pages_list; + } + #if 0 + for (i = 0; i < nr_pages; i++) { + pr_debug("page_to_pfn(pages[%i])=0x%lx\n", i, page_to_pfn(pages[i])); + } + #endif + + pr_debug("%s, vma->vm_start 0x%lx, vma->vm_end 0x%lx, (vm_end - vm_start) 0x%lx, vma->vm_pgoff 0x%lx, user_va 0x%llx, len 0x%lx, nr_pages 0x%lx\n", + __func__, vma->vm_start, vma->vm_end, + (vma->vm_end - vma->vm_start), vma->vm_pgoff, addr, len, nr_pages); + + /* construct new page table entry for the pages*/ + ret = vmf_replace_pages(vma, addr_aligned, + pages, nr_pages, prot); + if (ret) { + pr_err("err %d, failed to vmf_replace_pages!!!\n", ret); + ret = -EFAULT; + goto free_user_pages; + } + + /* Flush cache if the access to the user virtual address is uncached. */ + if (pgprot_val(prot) & _PAGE_UNCACHE) { + for (i = 0; i < nr_pages; i++) { + /* flush cache*/ + arch_sync_dma_for_device(page_to_phys(pages[i]), PAGE_SIZE, DMA_BIDIRECTIONAL); + /* put page back */ + put_page(pages[i]); + } + } + else { + for (i = 0; i < nr_pages; i++) { + /* put page back */ + put_page(pages[i]); + } + } + + kvfree(pages); + + return 0; + +free_user_pages: + for (i = 0; i < nr_pages; i++) { + /* put page back */ + put_page(pages[i]); + } +free_pages_list: + kvfree(pages); + + return ret; +} + +/** + * remap_malloc_buf - remap a range of memory allocated by malloc() API from user space. + * Normally, the CPU access to the user virtual address which is allocated by mallc() API is + * through cache. This remap_malloc_buf() API is to re-construct the pte table entry for the + * corresponding pages of the user virtual address as uncached memory, so that CPU access to + * the virtual address is uncached. + * @addr: virtual address which is got by malloc API from user space + * @len: the length of the memory allocated by malloc API + * @uncaced: if true, remap the memory as uncached, otherwise cached + * + * Return 0 if success. + * + * If uncached flag is true, the memory range of this virtual address will be flushed to make + * sure all the dirty data is evicted. + * + */ +int remap_malloc_buf(unsigned long addr, size_t len, bool uncaced) +{ + struct vm_area_struct *vma = NULL; + struct mm_struct *mm = current->mm; + pgprot_t prot; + int ret = 0; + + if (!len) { + pr_err("Invalid userptr size!!!\n"); + return -EINVAL; + } + + mmap_read_lock(mm); + vma = vma_lookup(mm, addr); + if (!vma) { + pr_err("%s, vma_lookup failed!\n", __func__); + mmap_read_unlock(mm); + return -EFAULT; + } + + pgprot_val(prot) = 0; + /* If true, add uncached property so that pfn_pte will use the pfn of system port to + constructs the page table entry. + Be carefull, do NOT change the value of the original vma->vm_page_prot*/ + if (uncaced) + prot = pgprot_dmacoherent(prot); + + ret = zap_and_replace_pages(vma, addr, len, prot); + mmap_read_unlock(mm); + + return ret; +} +EXPORT_SYMBOL_GPL(remap_malloc_buf); \ No newline at end of file diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-win2030.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-win2030.c index e3b6c28394b6..6ae7b0ecfb86 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-win2030.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-win2030.c @@ -1,6 +1,22 @@ -// SPDX-License-Identifier: GPL-2.0-only +// SPDX-License-Identifier: GPL-2.0 /* * Eswin DWC Ethernet linux driver + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: iangshuang */ #include @@ -66,6 +82,10 @@ struct dwc_qos_priv { struct gpio_desc *phy_reset; struct stmmac_priv *stmpriv; int phyled_cfgs[3]; + unsigned int dly_hsp_reg[3]; + unsigned int dly_param_1000m[3]; + unsigned int dly_param_100m[3]; + unsigned int dly_param_10m[3]; }; static int dwc_eth_dwmac_config_dt(struct platform_device *pdev, @@ -198,21 +218,15 @@ static int eswin_eth_sid_cfg(struct device *dev) static void dwc_qos_fix_speed(void *priv, unsigned int speed, unsigned int mode) { unsigned long rate = 125000000; - int err, data = 0; + int i, err, data = 0; struct dwc_qos_priv *dwc_priv = (struct dwc_qos_priv *)priv; switch (speed) { case SPEED_1000: rate = 125000000; - if ((dwc_priv->dev_id & 0x1) == 0) { - regmap_write(dwc_priv->hsp_regmap, 0x118, 0x800c8023); - regmap_write(dwc_priv->hsp_regmap, 0x11c, 0x0c0c0c0c); - regmap_write(dwc_priv->hsp_regmap, 0x114, 0x23232323); - } else { - regmap_write(dwc_priv->hsp_regmap, 0x218, 0x80268025); - regmap_write(dwc_priv->hsp_regmap, 0x21c, 0x26262626); - regmap_write(dwc_priv->hsp_regmap, 0x214, 0x25252525); + for (i = 0; i < 3; i++) { + regmap_write(dwc_priv->hsp_regmap, dwc_priv->dly_hsp_reg[i], dwc_priv->dly_param_1000m[i]); } if (dwc_priv->stmpriv) { @@ -226,14 +240,8 @@ static void dwc_qos_fix_speed(void *priv, unsigned int speed, unsigned int mode) case SPEED_100: rate = 25000000; - if ((dwc_priv->dev_id & 0x1) == 0) { - regmap_write(dwc_priv->hsp_regmap, 0x118, 0x803f8050); - regmap_write(dwc_priv->hsp_regmap, 0x11c, 0x3f3f3f3f); - regmap_write(dwc_priv->hsp_regmap, 0x114, 0x50505050); - } else { - regmap_write(dwc_priv->hsp_regmap, 0x218, 0x80588048); - regmap_write(dwc_priv->hsp_regmap, 0x21c, 0x58585858); - regmap_write(dwc_priv->hsp_regmap, 0x214, 0x48484848); + for (i = 0; i < 3; i++) { + regmap_write(dwc_priv->hsp_regmap, dwc_priv->dly_hsp_reg[i], dwc_priv->dly_param_100m[i]); } if (dwc_priv->stmpriv) { @@ -247,14 +255,8 @@ static void dwc_qos_fix_speed(void *priv, unsigned int speed, unsigned int mode) case SPEED_10: rate = 2500000; - if ((dwc_priv->dev_id & 0x1) == 0) { - regmap_write(dwc_priv->hsp_regmap, 0x118, 0x0); - regmap_write(dwc_priv->hsp_regmap, 0x11c, 0x0); - regmap_write(dwc_priv->hsp_regmap, 0x114, 0x0); - } else { - regmap_write(dwc_priv->hsp_regmap, 0x218, 0x0); - regmap_write(dwc_priv->hsp_regmap, 0x21c, 0x0); - regmap_write(dwc_priv->hsp_regmap, 0x214, 0x0); + for (i = 0; i < 3; i++) { + regmap_write(dwc_priv->hsp_regmap, dwc_priv->dly_hsp_reg[i], dwc_priv->dly_param_10m[i]); } if (dwc_priv->stmpriv) { @@ -342,11 +344,11 @@ static int dwc_qos_probe(struct platform_device *pdev, dwc_priv->dev = &pdev->dev; dwc_priv->phy_reset = devm_gpiod_get(&pdev->dev, "rst", GPIOD_OUT_LOW); if (IS_ERR(dwc_priv->phy_reset)) { - dev_err(&pdev->dev, "Reset gpio not specified\n"); - return -EINVAL; + dev_info(&pdev->dev, "Reset gpio not specified\n"); } - gpiod_set_value(dwc_priv->phy_reset, 0); + if (dwc_priv->phy_reset) + gpiod_set_value(dwc_priv->phy_reset, 0); dwc_priv->rgmii_sel = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "eswin,rgmiisel"); if (IS_ERR(dwc_priv->rgmii_sel)){ @@ -369,6 +371,30 @@ static int dwc_qos_probe(struct platform_device *pdev, dev_warn(&pdev->dev, "can't get led cfgs for 10Mbps mode (%d)\n", ret); } + ret = of_property_read_variable_u32_array(pdev->dev.of_node, "eswin,dly_hsp_reg", &dwc_priv->dly_hsp_reg[0], 3, 0); + if (ret != 3) { + dev_err(&pdev->dev, "can't get delay hsp reg.ret(%d)\n", ret); + return ret; + } + + ret = of_property_read_variable_u32_array(pdev->dev.of_node, "dly-param-1000m", &dwc_priv->dly_param_1000m[0], 3, 0); + if (ret != 3) { + dev_err(&pdev->dev, "can't get delay param for 1Gbps mode (%d)\n", ret); + return ret; + } + + ret = of_property_read_variable_u32_array(pdev->dev.of_node, "dly-param-100m", &dwc_priv->dly_param_100m[0], 3, 0); + if (ret != 3) { + dev_err(&pdev->dev, "can't get delay param for 100Mbps mode (%d)\n", ret); + return ret; + } + + ret = of_property_read_variable_u32_array(pdev->dev.of_node, "dly-param-10m", &dwc_priv->dly_param_10m[0], 3, 0); + if (ret != 3) { + dev_err(&pdev->dev, "can't get delay param for 10Mbps mode (%d)\n", ret); + return ret; + } + ret = of_property_read_u32_index(pdev->dev.of_node, "eswin,rgmiisel", 1, &rgmiisel_offset); if (ret) { dev_err(&pdev->dev, "can't get rgmiisel_offset (%d)\n", ret); @@ -487,7 +513,8 @@ static int dwc_qos_remove(struct platform_device *pdev) reset_control_assert(dwc_priv->rst); dwc_clks_config(dwc_priv, false); - devm_gpiod_put(&pdev->dev, dwc_priv->phy_reset); + if (dwc_priv->phy_reset) + devm_gpiod_put(&pdev->dev, dwc_priv->phy_reset); return 0; } diff --git a/drivers/regulator/es5340.c b/drivers/regulator/es5340.c index 30696296b210..e077fa2658bf 100644 --- a/drivers/regulator/es5340.c +++ b/drivers/regulator/es5340.c @@ -712,9 +712,7 @@ static struct regulator_desc es5340_regulator_desc = { static s32 es5340_init_data(struct ES5340_DRIVER_DATA *data, const struct regulation_constraints *constraints, u32 default_voltage) { - u8 value = 0; s32 ret = 0; - u16 new_value = 0; struct device *dev = &data->client->dev; dev_info(dev, diff --git a/drivers/soc/eswin/ai_driver/Kconfig b/drivers/soc/eswin/ai_driver/Kconfig index 84a135ee3d69..0044a4be10e5 100644 --- a/drivers/soc/eswin/ai_driver/Kconfig +++ b/drivers/soc/eswin/ai_driver/Kconfig @@ -2,6 +2,11 @@ config ESWIN_DSP tristate "Eswin DSP" default n +config DSP_PERF + bool "DSP PERF" + default n + depends on ESWIN_DSP + config ESWIN_NPU tristate "Eswin NPU" default n @@ -9,3 +14,8 @@ config ESWIN_NPU select ESWIN_DEV_DMA_BUF select ESWIN_IOMMU_RSV select ESWIN_RSVMEM_HEAP + +config NPU_PERF + bool "NPU PERF" + default n + depends on ESWIN_NPU \ No newline at end of file diff --git a/drivers/soc/eswin/ai_driver/dsp/Makefile b/drivers/soc/eswin/ai_driver/dsp/Makefile index e433e1af883b..d9fb51b3c14d 100755 --- a/drivers/soc/eswin/ai_driver/dsp/Makefile +++ b/drivers/soc/eswin/ai_driver/dsp/Makefile @@ -50,4 +50,8 @@ eic7700_dsp-y += dsp_platform.o dsp_sram.o dsp_firmware.o dsp_pool.o \ endif +ifeq ($(CONFIG_DSP_PERF),y) + BUILD_RELEASE = 2 +endif + ccflags-y += -DDSP_ENV_SIM=${DSP_ENV_SIM} -DBUILD_RELEASE=${BUILD_RELEASE} -DDEBUG_LEVEL=${DEBUG_LEVEL} -w diff --git a/drivers/soc/eswin/ai_driver/dsp/dsp_main.c b/drivers/soc/eswin/ai_driver/dsp/dsp_main.c index b32ffba9dcc8..5a2f3e97d9d8 100644 --- a/drivers/soc/eswin/ai_driver/dsp/dsp_main.c +++ b/drivers/soc/eswin/ai_driver/dsp/dsp_main.c @@ -58,6 +58,9 @@ #include #include #include +#include +#include + #include "eswin-khandle.h" #include "dsp_main.h" @@ -682,11 +685,16 @@ static inline void dsp_release(struct es_dsp *dsp) es_dsp_release(dsp->hw_arg); } -static inline int dsp_set_rate(struct es_dsp *dsp, unsigned long rate) +static inline int dsp_set_rate(struct es_dsp *dsp, unsigned long *rate) { return es_dsp_set_rate(dsp->hw_arg, rate); } +static inline int dsp_get_rate(struct es_dsp *dsp) +{ + return es_dsp_get_rate(dsp->hw_arg); +} + static int dsp_synchronize(struct es_dsp *dsp) { return es_dsp_sync(dsp); @@ -852,95 +860,6 @@ int __maybe_unused dsp_runtime_resume(struct device *dev) } EXPORT_SYMBOL(dsp_runtime_resume); -/** - * Called when opening rate file - * @param inode - * @param file - * @return - */ -static int dsp_rate_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -/** - * Called when reading rate file - */ -static ssize_t dsp_rate_read(struct file *flip, char __user *ubuf, size_t cnt, - loff_t *ppos) -{ -#define RUN_STR_SIZE 11 - struct es_dsp *dsp = flip->private_data; - char buf[RUN_STR_SIZE]; - int r; - - r = snprintf(buf, RUN_STR_SIZE, "%ld\n", dsp->rate); - - return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); -} -/** - * Called when writing rate file - */ -static ssize_t dsp_rate_write(struct file *flip, const char __user *ubuf, - size_t cnt, loff_t *ppos) -{ -#define SIZE_SMALL_BUF 256 - struct es_dsp *dsp = flip->private_data; - char buf[SIZE_SMALL_BUF] = { 0 }; - unsigned ret; - - if (cnt > SIZE_SMALL_BUF) - cnt = SIZE_SMALL_BUF - 1; - - if (copy_from_user(&buf, ubuf, cnt)) - return -EFAULT; - - if (0 == strncmp(buf, "5200000", strlen("5200000"))) { - dsp->rate = DSP_SUBSYS_LOWLOAD_CLK; /* FIXME spinlock? */ - } else if (0 == strncmp(buf, "1040000000", strlen("1040000000"))) { - dsp->rate = DSP_SUBSYS_HILOAD_CLK; - } else { - dev_err(dsp->dev, "invalid rate para %s\n", buf); - return -EFAULT; - } - ret = dsp_set_rate(dsp, dsp->rate); - if (0 != ret) { - dev_err(dsp->dev, "failed to set rate to %ldHZ", dsp->rate); - } else { - dev_info(dsp->dev, "set rate to %ldHZ", dsp->rate); - } - *ppos += cnt; - - return cnt; -} - -static const struct file_operations dsp_rate_fops = { - .open = dsp_rate_open, - .read = dsp_rate_read, - .write = dsp_rate_write, - .llseek = generic_file_llseek, -}; -static int dsp_debug_init(struct es_dsp *dsp) -{ - struct dentry *dir, *d; - char name[32]; - - scnprintf(name, ARRAY_SIZE(name), "dsp_%d", dsp->nodeid); - - dir = debugfs_create_dir(name, NULL); - if (IS_ERR(dir)) - return PTR_ERR(dir); - - d = debugfs_create_file("rate", S_IRUGO | S_IWUSR, dir, dsp, - &dsp_rate_fops); - if (IS_ERR(d)) - return PTR_ERR(d); - - dsp->debug_dentry = dir; - return 0; -} - #ifdef CONFIG_OF static const struct of_device_id es_dsp_hw_match[] = { { @@ -965,13 +884,48 @@ static void dsp_init_prio_array(struct es_dsp *dsp) set_bit(DSP_MAX_PRIO, array->bitmap); } -static int32_t dsp_probe_result = 0; +#if defined(CONFIG_PM_DEVFREQ) +/* devfreq target function to set frequency */ +static int dsp_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) +{ + struct es_dsp *dsp = dev_get_drvdata(dev); + + return dsp_set_rate(dsp, freq); +} + +static int dsp_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) +{ + struct es_dsp *dsp = dev_get_drvdata(dev); + unsigned long rate; + + rate = dsp_get_rate(dsp); + if (rate <= 0) { + dev_err(dsp->dev, "failed to get aclk: %d\n", rate); + return rate; + } + *freq = rate; + return 0; +} + +/* devfreq profile */ +static struct devfreq_dev_profile dsp_devfreq_profile = { + .initial_freq = DSP_SUBSYS_HILOAD_CLK, + .timer = DEVFREQ_TIMER_DELAYED, + .polling_ms = 1000, /* Poll every 1000ms to monitor load */ + .target = dsp_devfreq_target, + .get_cur_freq = dsp_devfreq_get_cur_freq, +}; +#endif +static int32_t dsp_probe_result = 0; static int es_dsp_hw_probe(struct platform_device *pdev) { int ret; char nodename[sizeof("es-dsp") + 3 * sizeof(int)]; struct es_dsp *dsp; +#if defined(CONFIG_PM_DEVFREQ) + struct devfreq *df; +#endif dsp = devm_kzalloc(&pdev->dev, sizeof(*dsp) + sizeof(struct es_dsp_stats) + @@ -1038,6 +992,23 @@ static int es_dsp_hw_probe(struct platform_device *pdev) __LINE__, ret); goto err_mbox_clk; } + +#if defined(CONFIG_PM_DEVFREQ) + /* Add OPP table from device tree */ + ret = dev_pm_opp_of_add_table(&pdev->dev); + if (ret) { + dsp_err("%s, %d, Failed to add OPP table\n", __func__, __LINE__); + goto err_dsp_devfreq; + } + + df = devm_devfreq_add_device(&pdev->dev, &dsp_devfreq_profile, "userspace", NULL); + if (IS_ERR(df)) { + dsp_err("%s, %d, add devfreq failed\n", __func__, __LINE__); + ret = PTR_ERR(df); + goto err_dsp_devfreq; + } +#endif + ret = es_dsp_clk_enable(dsp); if (ret) { dsp_err("%s, %d, clock enbale error.\n", __func__, __LINE__, @@ -1081,7 +1052,6 @@ static int es_dsp_hw_probe(struct platform_device *pdev) g_es_dsp[dsp->numa_id][dsp->process_id] = dsp; - dsp_debug_init(dsp); pm_runtime_mark_last_busy(dsp->dev); pm_runtime_put_autosuspend(dsp->dev); @@ -1100,6 +1070,10 @@ static int es_dsp_hw_probe(struct platform_device *pdev) err_tbu_power: es_dsp_clk_disable(dsp); err_dsp_clk: +#if defined(CONFIG_PM_DEVFREQ) + devm_devfreq_remove_device(dsp->dev, df); +err_dsp_devfreq: +#endif dsp_disable_mbox_clock(dsp); err_mbox_clk: es_dsp_unmap_resource(dsp); diff --git a/drivers/soc/eswin/ai_driver/dsp/dsp_platform.c b/drivers/soc/eswin/ai_driver/dsp/dsp_platform.c index 45c8bda644cc..342bdb20baae 100644 --- a/drivers/soc/eswin/ai_driver/dsp/dsp_platform.c +++ b/drivers/soc/eswin/ai_driver/dsp/dsp_platform.c @@ -318,7 +318,7 @@ int es_dsp_clk_enable(struct es_dsp *dsp) return 0; } -int es_dsp_set_rate(struct es_dsp_hw *hw, unsigned long rate) +int es_dsp_set_rate(struct es_dsp_hw *hw, unsigned long *rate) { struct es_dsp *dsp = hw->es_dsp; int ret; @@ -327,18 +327,24 @@ int es_dsp_set_rate(struct es_dsp_hw *hw, unsigned long rate) dsp_err("%s %d: failed to get device\n", __func__, __LINE__); return -ENXIO; } - rate = clk_round_rate(hw->aclk, rate); - if (rate > 0) { - ret = clk_set_rate(hw->aclk, rate); + + *rate = clk_round_rate(hw->aclk, *rate); + if (*rate > 0) { + ret = clk_set_rate(hw->aclk, *rate); if (ret) { dev_err(dsp->dev, "failed to set aclk: %d\n", ret); return ret; } } - dev_info(dsp->dev, "set device rate to %ldHZ\n", rate); + dev_info(dsp->dev, "set dev rate to %ldHZ\n", *rate); return 0; } +int es_dsp_get_rate(struct es_dsp_hw *hw) +{ + return clk_get_rate(hw->aclk); +} + void es_dsp_halt(struct es_dsp_hw *hw) { struct es_dsp *dsp = hw->es_dsp; @@ -1269,7 +1275,6 @@ int es_dsp_hw_init(struct es_dsp *dsp) hw->pts_iova = 0; goto err; } - es_dsp_set_rate(hw, dsp->rate); dev_dbg(dsp->dev, "firmware-name:%s.\n", dsp->firmware_name); return 0; err: diff --git a/drivers/soc/eswin/ai_driver/dsp/dsp_platform.h b/drivers/soc/eswin/ai_driver/dsp/dsp_platform.h index d538a9727242..40740cdfe21e 100644 --- a/drivers/soc/eswin/ai_driver/dsp/dsp_platform.h +++ b/drivers/soc/eswin/ai_driver/dsp/dsp_platform.h @@ -30,7 +30,7 @@ int es_dsp_send_irq(struct es_dsp_hw *, dsp_request_t *); int es_dsp_reboot_core(struct es_dsp_hw *); int es_dsp_enable(struct es_dsp_hw *); void es_dsp_disable(struct es_dsp_hw *); -int es_dsp_set_rate(struct es_dsp_hw *, unsigned long rate); +int es_dsp_set_rate(struct es_dsp_hw *, unsigned long *rate); void es_dsp_reset(struct es_dsp_hw *); void es_dsp_halt(struct es_dsp_hw *); void es_dsp_release(struct es_dsp_hw *); diff --git a/drivers/soc/eswin/ai_driver/dsp/dsp_platform_sim.c b/drivers/soc/eswin/ai_driver/dsp/dsp_platform_sim.c index ea9471381e02..2a7ba4077a99 100644 --- a/drivers/soc/eswin/ai_driver/dsp/dsp_platform_sim.c +++ b/drivers/soc/eswin/ai_driver/dsp/dsp_platform_sim.c @@ -262,7 +262,7 @@ void es_dsp_halt(struct es_dsp_hw *hw) void es_dsp_release(struct es_dsp_hw *hw) { } -long es_dsp_set_rate(struct es_dsp_hw *hw, unsigned long rate) +long es_dsp_set_rate(struct es_dsp_hw *hw, unsigned long *rate) { return 0; } diff --git a/drivers/soc/eswin/ai_driver/npu/Makefile b/drivers/soc/eswin/ai_driver/npu/Makefile index 29cbe78dd026..630aa94bc05f 100644 --- a/drivers/soc/eswin/ai_driver/npu/Makefile +++ b/drivers/soc/eswin/ai_driver/npu/Makefile @@ -3,6 +3,9 @@ LOG_LEVEL ?= 0 NPU_DEV_SIM ?= 0 SMALL_PEC_MAT ?= 0 +ifeq ($(CONFIG_NPU_PERF),y) + NPU_PERF_STATS = 2 +endif ccflags-y += -I$(src) ccflags-y += -I$(srctree)/drivers/soc/eswin ccflags-y += -I$(srctree)/drivers/memory/eswin/codacache/ @@ -22,7 +25,7 @@ ccflags-y += -DNPU_DBG #ccflags-y += -DCONV_DUMP ccflags-y += -DLOG_LEVEL=$(LOG_LEVEL) ccflags-y += -Wno-unused-function -ccflags-y += -Werror +#ccflags-y += -Werror ccflags-y += -Wno-int-to-pointer-cast obj-$(CONFIG_ESWIN_NPU) += eic7700_npu.o diff --git a/drivers/soc/eswin/ai_driver/npu/dla_driver.h b/drivers/soc/eswin/ai_driver/npu/dla_driver.h index 2101ccd1766e..11f22de8920b 100644 --- a/drivers/soc/eswin/ai_driver/npu/dla_driver.h +++ b/drivers/soc/eswin/ai_driver/npu/dla_driver.h @@ -31,7 +31,7 @@ #include #include #include - +#include #include "dla_interface.h" #include "hetero_common.h" @@ -67,6 +67,11 @@ struct nvdla_device { struct reset_control *rstc_e31_core; struct clk *e31_core_clk; + struct clk *core_clk; + struct clk *cfg_clk; + struct clk *mux_u_npu_core_3mux1_gfree; + struct clk *fixed_rate_clk_spll2_fout2; + struct clk *fixed_rate_clk_spll1_fout1; struct clk *mbox_pclk_device; struct clk *mbox_pclk; @@ -78,8 +83,11 @@ struct nvdla_device { u32 mbox_tx_lock_bit; u32 mbox_tx_irq_bit; spinlock_t mbox_lock; + unsigned long rate, volt; + struct mutex devfreq_lock; uint16_t *pause_op_list; + struct regulator *npu_regulator; }; void dla_reg_write(struct nvdla_device *dev, uint32_t addr, uint32_t value); diff --git a/drivers/soc/eswin/ai_driver/npu/npu_main.c b/drivers/soc/eswin/ai_driver/npu/npu_main.c index a742cbc58452..f6970d560605 100644 --- a/drivers/soc/eswin/ai_driver/npu/npu_main.c +++ b/drivers/soc/eswin/ai_driver/npu/npu_main.c @@ -73,9 +73,17 @@ #include "dla_buffer.h" #include "mailbox_regs.h" #include "nvdla_proc.h" +#include + +#if defined(CONFIG_PM_DEVFREQ) +#include +#include +#endif + MODULE_IMPORT_NS(DMA_BUF); #define DRIVER_NAME "eswin_npu" +#define NPU_CORE_CLK_HIGHEST 1500000000 int64_t dla_get_time_us(void) { @@ -324,6 +332,113 @@ struct nvdla_device *get_nvdla_dev(int i) return static_nvdla_dev[i]; } +#if defined(CONFIG_PM_DEVFREQ) +static int npu_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) +{ + struct nvdla_device *nvdla_dev = dev_get_drvdata(dev); + struct dev_pm_opp *opp; + unsigned long target_volt, target_rate; + unsigned long rate; + int ret; + + opp = devfreq_recommended_opp(dev, freq, flags); + if (IS_ERR(opp)) { + return PTR_ERR(opp); + } + + target_rate = dev_pm_opp_get_freq(opp); + target_volt = dev_pm_opp_get_voltage(opp); + dev_pm_opp_put(opp); + if (target_rate == nvdla_dev->rate) { + return 0; + } + mutex_lock(&nvdla_dev->devfreq_lock); + + if (target_rate > nvdla_dev->rate) { // rise freq + ret = regulator_set_voltage(nvdla_dev->npu_regulator, target_volt, target_volt); + if (ret) { + dev_err(dev, "Cannot set voltage %lu uV\n", target_volt); + goto out; + } + + ret = clk_set_parent(nvdla_dev->mux_u_npu_core_3mux1_gfree, nvdla_dev->fixed_rate_clk_spll1_fout1); + if (ret) { + dev_err(dev, "Cannot set target voltage %lu parent, (%d)\n", target_rate, ret); + goto err_parent; + } + mdelay(10); + rate = clk_round_rate(nvdla_dev->core_clk, target_rate); + ret = clk_set_rate(nvdla_dev->core_clk, rate); + if (ret != 0) + { + dev_err(dev, "failed to set core_clk: %d\n", ret); + goto err_rate; + + } + + } else { // lower freq + ret = clk_set_parent(nvdla_dev->mux_u_npu_core_3mux1_gfree, nvdla_dev->fixed_rate_clk_spll2_fout2); + if (ret) { + dev_err(dev, "Cannot set target voltage %lu parent, (%d)\n", target_rate, ret); + goto out; + } + + rate = clk_round_rate(nvdla_dev->core_clk, target_rate); + ret = clk_set_rate(nvdla_dev->core_clk, rate); + if (ret != 0) + { + dev_err(dev, "failed to set core_clk: %d\n", ret); + goto err_rate; + + } + + + ret = regulator_set_voltage(nvdla_dev->npu_regulator, target_volt, target_volt); + if (ret) { + dev_err(dev, "Cannot set voltage %lu uV\n", target_volt); + goto err_rate; + } + mdelay(10); + + } + + nvdla_dev->rate = clk_get_rate(nvdla_dev->core_clk); + if (nvdla_dev->rate != target_rate) { + dev_err(dev, "Got wrong frequency, Request %lu, Current %lu.\n", target_rate, nvdla_dev->rate); + ret = -EIO; + goto err_rate; + } + nvdla_dev->rate = target_rate; + nvdla_dev->volt = target_volt; + mutex_unlock(&nvdla_dev->devfreq_lock); + return 0; + +err_rate: + clk_set_parent(nvdla_dev->mux_u_npu_core_3mux1_gfree, nvdla_dev->fixed_rate_clk_spll1_fout1); +err_parent: + regulator_set_voltage(nvdla_dev->npu_regulator, nvdla_dev->volt, nvdla_dev->volt); +out: + mutex_unlock(&nvdla_dev->devfreq_lock); + return ret; +} + +static int npu_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) +{ + struct nvdla_device *nvdla_dev = dev_get_drvdata(dev); + + *freq = nvdla_dev->rate; + return 0; +} + +static struct devfreq_dev_profile npu_devfreq_profile = { + .initial_freq = NPU_CORE_CLK_HIGHEST, + .timer = DEVFREQ_TIMER_DELAYED, + .polling_ms = 1000, + .target = npu_devfreq_target, + .get_cur_freq = npu_devfreq_get_cur_freq, +}; +#endif + static int32_t npu_probe_result = 0; static int32_t edla_probe(struct platform_device *pdev) @@ -333,6 +448,10 @@ static int32_t edla_probe(struct platform_device *pdev) struct nvdla_device *nvdla_dev; struct device *dev = &pdev->dev; uint32_t version; +#if defined(CONFIG_PM_DEVFREQ) + struct devfreq *df = NULL; + struct dev_pm_opp *opp; +#endif dla_debug("%s enter.\n", __FUNCTION__); #if SMALL_PEC_MAT @@ -352,10 +471,23 @@ static int32_t edla_probe(struct platform_device *pdev) spin_lock_init(&nvdla_dev->nvdla_lock); mutex_init(&nvdla_dev->task_mutex); init_waitqueue_head(&nvdla_dev->event_wq); + mutex_init(&nvdla_dev->devfreq_lock); + + nvdla_dev->npu_regulator = devm_regulator_get(dev, "npu"); + err = regulator_enable(nvdla_dev->npu_regulator); + if (err < 0) + { + dla_error("npu_regulator enble error:%d\n\r", err); + regulator_put(nvdla_dev->npu_regulator); + nvdla_dev->npu_regulator = NULL; + return err; + } + err = npu_dt_node_resources(nvdla_dev); if (err) { dla_error("error, get hw resource, ret=%d\n", err); platform_set_drvdata(pdev, NULL); + regulator_disable(nvdla_dev->npu_regulator); return -EINVAL; } @@ -366,6 +498,7 @@ static int32_t edla_probe(struct platform_device *pdev) goto err_mem0; } + //npu configuration space, start from 0x51c00000 nvdla_dev->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(nvdla_dev->base)) { @@ -415,6 +548,36 @@ static int32_t edla_probe(struct platform_device *pdev) goto err_iomap_program; } +#if defined(CONFIG_PM_DEVFREQ) + /* Add OPP table from device tree */ + err = devm_pm_opp_of_add_table(dev); + if (err) { + dev_err(dev, "%s, %d, Failed to add OPP table, ret = %d.\n", __func__, __LINE__, err); + goto err_init_reset; + } + nvdla_dev->rate = clk_get_rate(nvdla_dev->core_clk); + opp = devfreq_recommended_opp(dev, &nvdla_dev->rate, 0); + if (IS_ERR(opp)) { + err = PTR_ERR(opp); + goto err_init_reset; + } + + nvdla_dev->rate = dev_pm_opp_get_freq(opp); + nvdla_dev->volt = dev_pm_opp_get_voltage(opp); + + regulator_set_voltage(nvdla_dev->npu_regulator, nvdla_dev->volt, nvdla_dev->volt); + + dev_pm_opp_put(opp); + + df = devm_devfreq_add_device(dev, &npu_devfreq_profile, "userspace", NULL); + if (IS_ERR(df)) { + err = PTR_ERR(df); + dev_err(dev, "%s, %d, Failed to add devfreq device, ret=%d.\n", __func__, __LINE__, err); + goto err_init_reset; + } +#endif + + pm_runtime_set_autosuspend_delay(dev, 5000); pm_runtime_use_autosuspend(dev); pm_runtime_set_active(dev); @@ -513,6 +676,7 @@ static int32_t edla_probe(struct platform_device *pdev) err_iomap_emission: release_mem_region(E31_EMISSION_DTIM_BASE + nvdla_dev->numa_id * NPU_DIE_REG_OFFSET, E31_EMISSION_DTIM_SIZE); err_mem0: + regulator_disable(nvdla_dev->npu_regulator); npu_put_dt_resources(nvdla_dev); npu_probe_result = err; return err; @@ -556,6 +720,8 @@ static int32_t __exit edla_remove(struct platform_device *pdev) ret = npu_disable_clock(nvdla_dev); npu_put_dt_resources(nvdla_dev); npu_remove_sysfs(pdev); + regulator_disable(nvdla_dev->npu_regulator); + if (nvdla_dev->pause_op_list) { vfree(nvdla_dev->pause_op_list); nvdla_dev->pause_op_list = NULL; @@ -625,19 +791,45 @@ int __maybe_unused npu_suspend(struct device *dev) npu_tbu_power(dev, false); npu_disable_clock(nvdla_dev); + + npu_dev_assert(nvdla_dev); + if ((NULL != nvdla_dev->npu_regulator) && (!IS_ERR(nvdla_dev->npu_regulator))) + { + regulator_disable(nvdla_dev->npu_regulator); + } + return 0; } int __maybe_unused npu_resume(struct device *dev) { int ret; - struct nvdla_device *ndev = dev_get_drvdata(dev); + int is_enable = 0; - ret = npu_enable_clock(ndev); + struct nvdla_device *nvdla_dev = dev_get_drvdata(dev); + + if ((NULL != nvdla_dev->npu_regulator) && (!IS_ERR(nvdla_dev->npu_regulator))) + { + is_enable = regulator_is_enabled(nvdla_dev->npu_regulator); + if(0 == is_enable) + { + mdelay(20); + } + ret = regulator_enable(nvdla_dev->npu_regulator); + if(ret < 0) + { + dla_error("%s, %d regulator_enable eror\n", __func__, __LINE__); + } + if(0 == is_enable) + { + mdelay(20); + } + } + ret = npu_enable_clock(nvdla_dev); if (ret < 0) { return ret; } - ret = npu_hardware_reset(ndev); + ret = npu_hardware_reset(nvdla_dev); if (ret) { dla_error("hardware reset error, ret=%d.\n", ret); return -EIO; @@ -645,11 +837,11 @@ int __maybe_unused npu_resume(struct device *dev) pm_runtime_get_noresume(dev); - ret = npu_init_reset(ndev); + ret = npu_init_reset(nvdla_dev); if (ret < 0) { goto err_reset; } - ret = npu_init_mbox(ndev); + ret = npu_init_mbox(nvdla_dev); if (ret) { dev_err(dev, "npu init mailbox error, ret = %d.\n", ret); goto err_reset; @@ -657,14 +849,14 @@ int __maybe_unused npu_resume(struct device *dev) npu_tbu_power(dev, true); /* config streamID of NPU_DMA */ - ret = npu_e31_load_fw(ndev); + ret = npu_e31_load_fw(nvdla_dev); if (ret) { dev_err(dev, "load e31 fw error.\n"); goto err_load_firm; } - npu_dma_sid_cfg(ndev->base, WIN2030_SID_NPU_DMA); - npu_hw_init(ndev); - ret = npu_init_ipc(ndev); + npu_dma_sid_cfg(nvdla_dev->base, WIN2030_SID_NPU_DMA); + npu_hw_init(nvdla_dev); + ret = npu_init_ipc(nvdla_dev); if (ret) { dev_err(dev, "npu init ipc error.\n"); goto err_ipc; @@ -672,14 +864,15 @@ int __maybe_unused npu_resume(struct device *dev) pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); + return 0; err_ipc: - npu_init_reset(ndev); + npu_init_reset(nvdla_dev); err_load_firm: npu_tbu_power(dev, false); err_reset: - npu_disable_clock(ndev); + npu_disable_clock(nvdla_dev); return ret; } diff --git a/drivers/soc/eswin/ai_driver/npu/nvdla_hw.c b/drivers/soc/eswin/ai_driver/npu/nvdla_hw.c index 096bcde3bcad..923b8e36175e 100644 --- a/drivers/soc/eswin/ai_driver/npu/nvdla_hw.c +++ b/drivers/soc/eswin/ai_driver/npu/nvdla_hw.c @@ -260,6 +260,35 @@ int npu_dev_reset(struct nvdla_device *nvdla_dev) return 0; } + +int npu_dev_assert(struct nvdla_device *nvdla_dev) +{ + int ret = 0; + + ret = reset_control_assert(nvdla_dev->rstc_e31_core); + WARN_ON(0 != ret); + + /*reset npu core*/ + ret = npu_core_rst(0, false); + if (ret) { + dev_err(&nvdla_dev->pdev->dev, "npu_core_rst fail,error: %d.\n", + ret); + return ret; + } + + /*reset npu cfg*/ + ret = npu_cfg_rst(0, false); + if (ret) { + dev_err(&nvdla_dev->pdev->dev, "npu_core_rst fail,error: %d.\n", + ret); + return ret; + } + + return 0; +} + + + int npu_init_reset(struct nvdla_device *nvdla_dev) { struct platform_device *pdev = nvdla_dev->pdev; @@ -826,6 +855,44 @@ int npu_dt_node_resources(struct nvdla_device *nvdla_dev) dev_err(&pdev->dev, "failed to get core_clk: %d\n", ret); return ret; } + nvdla_dev->core_clk = devm_clk_get(&pdev->dev, "core_clk"); + if (IS_ERR(nvdla_dev->core_clk)) { + ret = PTR_ERR(nvdla_dev->core_clk); + nvdla_dev->core_clk = NULL; + dev_err(&pdev->dev, "failed to get core clk: %d.\n", ret); + return ret; + } + nvdla_dev->cfg_clk = devm_clk_get(&pdev->dev, "cfg_clk"); + if (IS_ERR(nvdla_dev->cfg_clk)) { + ret = PTR_ERR(nvdla_dev->cfg_clk); + nvdla_dev->cfg_clk = NULL; + dev_err(&pdev->dev, "failed to get cfg clk: %d.\n", ret); + return ret; + } + nvdla_dev->mux_u_npu_core_3mux1_gfree = devm_clk_get(&pdev->dev, "mux_u_npu_core_3mux1_gfree"); + if (IS_ERR(nvdla_dev->mux_u_npu_core_3mux1_gfree)) { + ret = PTR_ERR(nvdla_dev->mux_u_npu_core_3mux1_gfree); + nvdla_dev->mux_u_npu_core_3mux1_gfree = NULL; + dev_err(&pdev->dev, "failed to get mux_u_npu_core_3mux1_gfree clk: %d.\n", ret); + return ret; + } + + nvdla_dev->fixed_rate_clk_spll2_fout2 = devm_clk_get(&pdev->dev, "fixed_rate_clk_spll2_fout2"); + if (IS_ERR(nvdla_dev->fixed_rate_clk_spll2_fout2)) { + ret = PTR_ERR(nvdla_dev->fixed_rate_clk_spll2_fout2); + nvdla_dev->fixed_rate_clk_spll2_fout2 = NULL; + dev_err(&pdev->dev, "failed to get fixed_rate_clk_spll2_fout2 clk: %d.\n", ret); + return ret; + } + + nvdla_dev->fixed_rate_clk_spll1_fout1 = devm_clk_get(&pdev->dev, "fixed_rate_clk_spll1_fout1"); + if (IS_ERR(nvdla_dev->fixed_rate_clk_spll1_fout1)) { + ret = PTR_ERR(nvdla_dev->fixed_rate_clk_spll1_fout1); + nvdla_dev->fixed_rate_clk_spll1_fout1 = NULL; + dev_err(&pdev->dev, "failed to get fixed_rate_clk_spll1_fout1 clk: %d.\n", ret); + return ret; + } + //nvdla_dev->rstc_e31_core = devm_reset_control_get_optional_exclusive( nvdla_dev->rstc_e31_core = devm_reset_control_get_optional( &pdev->dev, "e31_core"); @@ -976,17 +1043,29 @@ int npu_disable_clock(struct nvdla_device *ndev) { npu_disable_mbox_clock(ndev); clk_disable_unprepare(ndev->e31_core_clk); - return npu_clk_gate_set(ndev->numa_id, false); + + clk_disable_unprepare(ndev->core_clk); + + clk_disable_unprepare(ndev->cfg_clk); + return 0; } int npu_enable_clock(struct nvdla_device *ndev) { int ret; - ret = npu_clk_gate_set(ndev->numa_id, true); - if (ret < 0) { - dla_error("npu_clk_gate_set failed.\n"); + + ret = clk_prepare_enable(ndev->cfg_clk); + if (ret) { + dla_error("failed to enable cfg_clk: %d\n", ret); return ret; } + + ret = clk_prepare_enable(ndev->core_clk); + if (ret) { + dla_error("failed to enable core_clk: %d\n", ret); + goto core_clk; + } + ret = clk_prepare_enable(ndev->e31_core_clk); if (ret < 0) { dla_error("npu enable e31 core clk err.\n"); @@ -1001,7 +1080,9 @@ int npu_enable_clock(struct nvdla_device *ndev) err_mbox_clk: clk_disable_unprepare(ndev->e31_core_clk); err_e31_clk: - npu_clk_gate_set(ndev->numa_id, false); + clk_disable_unprepare(ndev->core_clk); +core_clk: + clk_disable_unprepare(ndev->cfg_clk); return ret; } diff --git a/drivers/soc/eswin/ai_driver/npu/nvdla_lowlevel.h b/drivers/soc/eswin/ai_driver/npu/nvdla_lowlevel.h index 6d26b9470152..a5d3ab9b088e 100644 --- a/drivers/soc/eswin/ai_driver/npu/nvdla_lowlevel.h +++ b/drivers/soc/eswin/ai_driver/npu/nvdla_lowlevel.h @@ -42,6 +42,7 @@ int npu_create_sysfs(struct platform_device *pdev); int npu_hardware_reset(struct nvdla_device *nvdla_dev); int npu_dev_reset(struct nvdla_device *nvdla_dev); +int npu_dev_assert(struct nvdla_device *nvdla_dev); int npu_init_reset(struct nvdla_device *nvdla_dev); void npu_dma_sid_cfg(void __iomem *npu_subsys_base, u32 sid); diff --git a/drivers/soc/eswin/ai_driver/npu/user_context.c b/drivers/soc/eswin/ai_driver/npu/user_context.c index 47dadc142fed..6679f371b06b 100644 --- a/drivers/soc/eswin/ai_driver/npu/user_context.c +++ b/drivers/soc/eswin/ai_driver/npu/user_context.c @@ -600,6 +600,20 @@ static int commit_new_io_tensor(struct user_context *uctx, void *arg) static struct win_engine *get_engine_from_file(struct file *file); +static int runtime_try_lock(struct user_context *uctx, struct file *file) +{ + struct win_engine *engine; + engine = get_engine_from_file(file); + + if (down_trylock(&engine->runtime_sem)) { + return -EINTR; + } + BUG_ON(atomic_read(&uctx->lock_status) != NPU_RT_MUTX_IDLE); + atomic_set(&uctx->lock_status, NPU_RT_MUTX_LOCKED); + dla_debug("try %s, %d locked\n", __func__, __LINE__); + return 0; +} + static int runtime_lock_request(struct user_context *uctx, struct file *file, unsigned int cmd) { @@ -607,15 +621,7 @@ static int runtime_lock_request(struct user_context *uctx, struct file *file, struct win_engine *engine; engine = get_engine_from_file(file); - if (cmd == ES_NPU_IOCTL_MUTEX_TRYLOCK) { - if (down_trylock(&engine->runtime_sem)) { - return -EINTR; - } - BUG_ON(atomic_read(&uctx->lock_status) != NPU_RT_MUTX_IDLE); - atomic_set(&uctx->lock_status, NPU_RT_MUTX_LOCKED); - dla_debug("try %s, %d locked\n", __func__, __LINE__); - - } else if (cmd == ES_NPU_IOCTL_MUTEX_LOCK) { + if (cmd == ES_NPU_IOCTL_MUTEX_LOCK) { if (down_interruptible(&engine->runtime_sem)) { return -EINTR; } @@ -893,9 +899,10 @@ static long npu_dev_ioctl(struct file *file, unsigned int cmd, case ES_NPU_IOCTL_TASK_SUBMIT: ret = commit_new_io_tensor(uctx, &win_arg); break; - case ES_NPU_IOCTL_MUTEX_LOCK: - case ES_NPU_IOCTL_MUTEX_UNLOCK: case ES_NPU_IOCTL_MUTEX_TRYLOCK: + return runtime_try_lock(uctx, file); + case ES_NPU_IOCTL_MUTEX_UNLOCK: + case ES_NPU_IOCTL_MUTEX_LOCK: ret = runtime_lock_request(uctx, file, cmd); break; case ES_NPU_IOCTL_HETERO_CMD: diff --git a/drivers/staging/media/eswin/dewarp/vvcam_dwe_driver.c b/drivers/staging/media/eswin/dewarp/vvcam_dwe_driver.c index f1ab8835ceac..d462277fecc6 100644 --- a/drivers/staging/media/eswin/dewarp/vvcam_dwe_driver.c +++ b/drivers/staging/media/eswin/dewarp/vvcam_dwe_driver.c @@ -74,6 +74,8 @@ #include #include #include +#include +#include #include "dw200_fe.h" #include "dw200_ioctl.h" @@ -1041,6 +1043,66 @@ static int vvcam_sys_reset_release(dw_clk_rst_t *dw_crg) } \ } while (0) +int dewarp_set_aclk_rate(dw_clk_rst_t *dw_crg, unsigned long *rate) +{ + int ret; + + *rate = clk_round_rate(dw_crg->aclk, *rate); + if (*rate > 0) { + ret = clk_set_rate(dw_crg->aclk, *rate); + if (ret) { + dev_err(dw_crg->dev, "failed to set aclk: %d\n", ret); + return ret; + } + dev_info(dw_crg->dev, "set dev rate to %ldHZ\n", *rate); + } + return 0; +} + +int dewarp_get_aclk_rate(dw_clk_rst_t *dw_crg) +{ + unsigned long rate; + rate = clk_get_rate(dw_crg->aclk); + dev_info(dw_crg->dev, "get dev rate %ldHZ\n", rate); + return rate; +} + +/* devfreq target function to set frequency */ +static int dewarp_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) +{ + struct es_dewarp_driver_dev *pdriver_dev = dev_get_drvdata(dev); + struct dw200_subdev *pdwe_dev; + + pdwe_dev = &pdriver_dev->hw_dev; + return dewarp_set_aclk_rate(&pdwe_dev->dw_crg, freq); +} + +static int dewarp_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) +{ + struct es_dewarp_driver_dev *pdriver_dev = dev_get_drvdata(dev); + struct dw200_subdev *pdwe_dev; + + pdwe_dev = &pdriver_dev->hw_dev; + unsigned long rate; + + rate = dewarp_get_aclk_rate(&pdwe_dev->dw_crg); + if (rate <= 0) { + dev_err(dev, "failed to get aclk: %ld\n", rate); + return rate; + } + *freq = rate; + return 0; +} + +/* devfreq profile */ +static struct devfreq_dev_profile dewarp_devfreq_profile = { + .initial_freq = VVCAM_AXI_CLK_HIGHEST, + .timer = DEVFREQ_TIMER_DELAYED, + .polling_ms = 1000, /* Poll every 1000ms to monitor load */ + .target = dewarp_devfreq_target, + .get_cur_freq = dewarp_devfreq_get_cur_freq, +}; + static int vvcam_sys_clk_config(dw_clk_rst_t *dw_crg) { int ret = 0; @@ -1212,6 +1274,7 @@ static int es_dewarp_probe(struct platform_device *pdev) struct es_dewarp_driver_dev *pdriver_dev; struct dw200_subdev *pdwe_dev; char debug_dw200_reset[64] = "dw200_reset"; + struct devfreq *df; int id = 0; if (pdev->id >= NUM_DEVICES) { @@ -1246,6 +1309,19 @@ static int es_dewarp_probe(struct platform_device *pdev) return ret; } + /* Add OPP table from device tree */ + ret = dev_pm_opp_of_add_table(&pdev->dev); + if (ret) { + pr_err("%s, %d, Failed to add OPP table\n", __func__, __LINE__); + return ret; + } + + df = devm_devfreq_add_device(&pdev->dev, &dewarp_devfreq_profile, "userspace", NULL); + if (IS_ERR(df)) { + pr_err("%s, %d, add devfreq failed\n", __func__, __LINE__); + return ret; + } + pdwe_dev->dw_crg.dev = &pdev->dev; ret = vvcam_sys_clk_prepare(&pdwe_dev->dw_crg); if (ret) { @@ -1387,6 +1463,7 @@ static int es_dewarp_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP static int dewarp_runtime_suspend(struct device *dev) { struct es_dewarp_driver_dev *pdriver_dev = dev_get_drvdata(dev); @@ -1462,6 +1539,7 @@ static int dewarp_resume(struct device *dev) return ret; } +#endif static const struct dev_pm_ops dewarp_pm_ops = { SET_RUNTIME_PM_OPS(dewarp_runtime_suspend, dewarp_runtime_resume, NULL) diff --git a/drivers/staging/media/eswin/hae/hal/os/linux/kernel/gc_hal_kernel_driver.c b/drivers/staging/media/eswin/hae/hal/os/linux/kernel/gc_hal_kernel_driver.c index a428dcd84af5..91d7c78566d5 100644 --- a/drivers/staging/media/eswin/hae/hal/os/linux/kernel/gc_hal_kernel_driver.c +++ b/drivers/staging/media/eswin/hae/hal/os/linux/kernel/gc_hal_kernel_driver.c @@ -1393,11 +1393,16 @@ static int __devinit viv_dev_probe(struct platform_device *pdev) if (platform->ops->adjustParam) { /* Override default module param. */ + gceSTATUS status; activeDeviceCount++; - if(gcvSTATUS_MORE_DATA == platform->ops->adjustParam(platform, &platform->params)){ + status = platform->ops->adjustParam(platform, &platform->params); + if(gcvSTATUS_MORE_DATA == status){ gcmkPRINT("hae loaded first device, waiting for another..."); _SyncModuleParam(&platform->params); return 0; + } else if (!gcmIS_SUCCESS(status)){ + gcmkPRINT("hae adjust param error, status=%d", status); + return -1; } } diff --git a/drivers/staging/media/eswin/hae/hal/os/linux/kernel/platform/eswin/gc_hal_kernel_platform_win2030.c b/drivers/staging/media/eswin/hae/hal/os/linux/kernel/platform/eswin/gc_hal_kernel_platform_win2030.c index 580267770992..f2cebd459f41 100644 --- a/drivers/staging/media/eswin/hae/hal/os/linux/kernel/platform/eswin/gc_hal_kernel_platform_win2030.c +++ b/drivers/staging/media/eswin/hae/hal/os/linux/kernel/platform/eswin/gc_hal_kernel_platform_win2030.c @@ -90,6 +90,9 @@ # include # include #endif +#include +#include +#define G2D_HILOAD_CLK 1040000000 /* Disable MSI for internal FPGA build except PPC */ #if gcdFPGA_BUILD @@ -159,7 +162,10 @@ struct gpu_power_domain { int num_domains; struct device **power_dev; struct clk *clks[gcdDEVICE_COUNT][gcvCLKS_COUNT]; + struct device *dev[gcdDEVICE_COUNT]; + struct devfreq *df[gcdDEVICE_COUNT]; }; +static struct gpu_power_domain gpd; static struct _gpu_reset { struct reset_control *rsts[gcdDEVICE_COUNT][gcvRST_COUNT]; @@ -217,7 +223,57 @@ static void show_clk_status(int dieIndex) iounmap(g2d_top_ptr); } -struct gpu_power_domain gpd; +#if defined(CONFIG_PM_DEVFREQ) +static int g2d_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) { + int i, j; + unsigned long rate = *freq; + int ret = -1; + struct clk *aclk; + + for (i = 0; i < gpd.num_domains; i++) { + if (gpd.dev[i] != dev) continue; + for (j = 0; j < nc_of_clks; j++) { + if (strcmp("g2d_clk", clk_names[j]) && strcmp("g2d_aclk", clk_names[j])) continue; + aclk = gpd.clks[i][j]; + rate = clk_round_rate(aclk, rate); + if (rate > 0) { + ret = clk_set_rate(aclk, rate); + if (ret) { + dev_err(dev, "failed to set %s clk: %d\n", clk_names[j], ret); + return ret; + } + } + dev_info(dev, "set %s rate to %ldHZ\n", clk_names[j], rate); + } + } + if (!ret) { + *freq = rate; + return 0; + } else { + dev_err(dev, "set rate to %ldHZ\n failed", rate); + return -1; + } +} +static int g2d_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) { + int i, j; + for (i = 0; i < gpd.num_domains; i++) { + if (gpd.dev[i] != dev) continue; + for (j = 0; j < nc_of_clks; j++) { + if (!strcmp("g2d_clk", clk_names[j])) { + return clk_get_rate(gpd.clks[i][j]); + } + } + } + return 0; +} +static struct devfreq_dev_profile g2d_devfreq_profile = { + .initial_freq = G2D_HILOAD_CLK, + .timer = DEVFREQ_TIMER_DELAYED, + .polling_ms = 1000, /* Poll every 1000ms to monitor load */ + .target = g2d_devfreq_target, + .get_cur_freq = g2d_devfreq_get_cur_freq, +}; +#endif gceSTATUS _set_clock(gcsPLATFORM *Platform, gctUINT32 DevIndex, gceCORE GPU, gctBOOL Enable) @@ -411,6 +467,9 @@ static int gpu_parse_dt(struct platform_device *pdev, gcsMODULE_PARAMETERS *para const char *str; int dieIndex = 0; int peerDieIndex; +#if defined(CONFIG_PM_DEVFREQ) + struct devfreq *df; +#endif gcmSTATIC_ASSERT(gcvCORE_COUNT == gcmCOUNTOF(core_names), "core_names array does not match core types"); @@ -548,7 +607,18 @@ static int gpu_parse_dt(struct platform_device *pdev, gcsMODULE_PARAMETERS *para } g2d_reset(&pdev->dev, dieIndex, 1); - +#if defined(CONFIG_PM_DEVFREQ) + if (dev_pm_opp_of_add_table(&pdev->dev)) { + gcmkPRINT("%s, %d, Failed to add OPP table", __func__, __LINE__); + return gcvSTATUS_INVALID_OBJECT; + } + df = devm_devfreq_add_device(&pdev->dev, &g2d_devfreq_profile, "userspace", NULL); + if (IS_ERR(df)) { + gcmkPRINT("%s, %d, add devfreq failed", __func__, __LINE__); + return gcvSTATUS_INVALID_OBJECT; + } + gpd.df[dieIndex] = df; +#endif show_clk_status(dieIndex); params->devCount++; @@ -775,10 +845,18 @@ gceSTATUS _AdjustParam(gcsPLATFORM *Platform, gcsMODULE_PARAMETERS *Args) { int ret; +#if defined(CONFIG_PM_DEVFREQ) + int i; +#endif #if gcdSUPPORT_DEVICE_TREE_SOURCE ret = gpu_parse_dt(Platform->device, Args); - if(!ret){ + if(gcmIS_SUCCESS(ret)){ gpu_add_power_domains(Platform->device, Args); +#if defined(CONFIG_PM_DEVFREQ) + for (i = 0; i < gcdDEVICE_COUNT; i++) { + gpd.dev[i] = Args->devices[i]; + } +#endif } #elif USE_LINUX_PCIE struct _gcsPLATFORM_PCIE *pcie_platform = (struct _gcsPLATFORM_PCIE *)Platform; @@ -1204,6 +1282,9 @@ gceSTATUS _DmaExit(gcsPLATFORM *Platform) struct device *dev = Platform->params.devices[i]; if (!dev) continue; g2d_reset(dev, i, 0); +#if defined(CONFIG_PM_DEVFREQ) + devm_devfreq_remove_device(dev, gpd.df[i]); +#endif show_clk_status(i); } return gcvSTATUS_OK; diff --git a/drivers/staging/media/eswin/vdec/hantro_dec.c b/drivers/staging/media/eswin/vdec/hantro_dec.c index 7c4de300d6e6..780b2561ab20 100644 --- a/drivers/staging/media/eswin/vdec/hantro_dec.c +++ b/drivers/staging/media/eswin/vdec/hantro_dec.c @@ -106,6 +106,11 @@ #include "dts_parser.h" #include "vdec_allocator.h" +#if defined(CONFIG_PM_DEVFREQ) +#include +#include +#endif + #define LOG_TAG DEC_DEV_NAME ":main" #include "vc_drv_log.h" @@ -3945,10 +3950,68 @@ int d1_clk_reset_init(void) return 0; } +#if defined(CONFIG_PM_DEVFREQ) +static int vdec_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) +{ + int ret; + vdec_clk_rst_t *vcrt = dev_get_drvdata(dev); + + LOG_DBG("%s:%d, dev = %p, freq = %lu\n", __func__, __LINE__, dev, *freq); + *freq = clk_round_rate(vcrt->jd_clk, *freq); + if (*freq > 0) { + ret = clk_set_rate(vcrt->jd_clk, *freq); + if (ret) { + LOG_ERR("%d: failed to set jd_clk: %d\n", __LINE__, ret); + return ret; + } + LOG_DBG("set jd_clk to %ldHZ\n", *freq); + } else { + LOG_ERR("%d: failed to round rate for jd_clk %ld\n", __LINE__, *freq); + return -1; + } + + *freq = clk_round_rate(vcrt->vd_clk, *freq); + if (*freq > 0) { + ret = clk_set_rate(vcrt->vd_clk, *freq); + if (ret) { + LOG_ERR("%d: failed to set vd_clk: %d\n", __LINE__, ret); + return ret; + } + LOG_DBG("set vd_clk to %ldHZ\n", *freq); + } else { + LOG_ERR("%d: failed to round rate for vd_clk %ld\n", __LINE__, *freq); + return -1; + } + + return 0; +} + +static int vdec_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) +{ + vdec_clk_rst_t *vcrt = dev_get_drvdata(dev); + + *freq = clk_get_rate(vcrt->vd_clk); + + return 0; +} + +/** devfreq profile */ +static struct devfreq_dev_profile vdec_devfreq_profile = { + .initial_freq = VDEC_SYS_CLK_HIGHEST, + .timer = DEVFREQ_TIMER_DELAYED, + .polling_ms = 1000, /** Poll every 1000ms to monitor load */ + .target = vdec_devfreq_target, + .get_cur_freq = vdec_devfreq_get_cur_freq, +}; +#endif /** CONFIG_PM_DEVFREQ*/ + static int hantro_vdec_probe(struct platform_device *pdev) { int numa_id; int ret, vdec_dev_num = 0; +#if defined(CONFIG_PM_DEVFREQ) + struct devfreq *df = NULL; +#endif vdec_clk_rst_t *vcrt = devm_kzalloc(&pdev->dev, sizeof(vdec_clk_rst_t), GFP_KERNEL); if (!vcrt) { LOG_ERR("malloc drvdata failed\n"); @@ -3970,6 +4033,20 @@ static int hantro_vdec_probe(struct platform_device *pdev) LOG_INFO("initializing vdec, numa id %d\n", numa_id); +#if defined(CONFIG_PM_DEVFREQ) + /* Add OPP table from device tree */ + ret = dev_pm_opp_of_add_table(&pdev->dev); + if (ret) { + LOG_ERR("%s, %d, failed to add OPP table\n", __func__, __LINE__); + return -1; + } + df = devm_devfreq_add_device(&pdev->dev, &vdec_devfreq_profile, "userspace", NULL); + if (IS_ERR(df)) { + LOG_ERR("%s, %d, add devfreq failed\n", __func__, __LINE__); + return -1; + } +#endif /** CONFIG_PM_DEVFREQ*/ + ret = vdec_sys_reset_init(pdev, vcrt); if (ret < 0) { LOG_ERR("vdec: reset initialization failed"); diff --git a/drivers/staging/media/eswin/venc/vc8000e_driver.c b/drivers/staging/media/eswin/venc/vc8000e_driver.c index 97743c8172cd..0244069626c1 100644 --- a/drivers/staging/media/eswin/venc/vc8000e_driver.c +++ b/drivers/staging/media/eswin/venc/vc8000e_driver.c @@ -15,6 +15,11 @@ #include #include +#if defined(CONFIG_PM_DEVFREQ) +#include +#include +#endif + #include "vc8000_driver.h" #define LOG_TAG VENC_DEV_NAME ":main" @@ -821,12 +826,72 @@ int enc_reset_system(u32 core_id) { } /** end of interface functions*/ +#if defined(CONFIG_PM_DEVFREQ) +static int venc_devfreq_target(struct device *dev, unsigned long *freq, u32 flags) +{ + int ret; + venc_dev_prvdata *prvdata = dev_get_drvdata(dev); + venc_clk_rst_t *vcrt = &prvdata->vcrt; + + LOG_DBG("%s:%d, dev = %p, freq = %lu\n", __func__, __LINE__, dev, *freq); + *freq = clk_round_rate(vcrt->je_clk, *freq); + if (*freq > 0) { + ret = clk_set_rate(vcrt->je_clk, *freq); + if (ret) { + LOG_ERR("Video encoder: failed to set je_clk: %d\n", ret); + return ret; + } + LOG_DBG("VE set je_clk to %ldHZ\n", *freq); + } else { + LOG_ERR("Video encoder: failed to round rate for je_clk %ld\n", *freq); + return -1; + } + + *freq = clk_round_rate(vcrt->ve_clk, *freq); + if (*freq > 0) { + ret = clk_set_rate(vcrt->ve_clk, *freq); + if (ret) { + LOG_ERR("Video encoder: failed to set ve_clk: %d\n", ret); + return ret; + } + LOG_DBG("VE set ve_clk to %ldHZ\n", *freq); + } else { + LOG_ERR("Video encoder: failed to round rate for ve_clk %ld\n", *freq); + return -1; + } + + return 0; +} + +static int venc_devfreq_get_cur_freq(struct device *dev, unsigned long *freq) +{ + venc_dev_prvdata *prvdata = dev_get_drvdata(dev); + venc_clk_rst_t *vcrt = &prvdata->vcrt; + + *freq = clk_get_rate(vcrt->ve_clk); + + return 0; +} + +/** devfreq profile */ +static struct devfreq_dev_profile venc_devfreq_profile = { + .initial_freq = VENC_SYS_CLK_HIGHEST, + .timer = DEVFREQ_TIMER_DELAYED, + .polling_ms = 1000, /** Poll every 1000ms to monitor load */ + .target = venc_devfreq_target, + .get_cur_freq = venc_devfreq_get_cur_freq, +}; +#endif /** CONFIG_PM_DEVFREQ*/ + static int hantro_venc_probe(struct platform_device *pdev) { static int pdev_count = 0; int ret, numa_id, venc_dev_num = 0; venc_dev_prvdata *prvdata = devm_kzalloc(&pdev->dev, sizeof(venc_dev_prvdata), GFP_KERNEL); venc_clk_rst_t *vcrt = &prvdata->vcrt; +#if defined(CONFIG_PM_DEVFREQ) + struct devfreq *df = NULL; +#endif venc_dev_num = venc_device_nodes_check(); if (venc_dev_num <= 0) { @@ -842,6 +907,20 @@ static int hantro_venc_probe(struct platform_device *pdev) LOG_INFO("initializing venc, numa id %d\n", numa_id); +#if defined(CONFIG_PM_DEVFREQ) + /* Add OPP table from device tree */ + ret = dev_pm_opp_of_add_table(&pdev->dev); + if (ret) { + LOG_ERR("%s, %d, Failed to add OPP table\n", __func__, __LINE__); + return -1; + } + df = devm_devfreq_add_device(&pdev->dev, &venc_devfreq_profile, "userspace", NULL); + if (IS_ERR(df)) { + LOG_ERR("%s, %d, add devfreq failed\n", __func__, __LINE__); + return -1; + } +#endif /** CONFIG_PM_DEVFREQ*/ + if (!numa_id) { ret = venc_sys_reset_init(pdev, vcrt); if (ret < 0) { diff --git a/include/linux/dmabuf-heap-import-helper.h b/include/linux/dmabuf-heap-import-helper.h index 9a474f6594e7..d4acd7c5177c 100644 --- a/include/linux/dmabuf-heap-import-helper.h +++ b/include/linux/dmabuf-heap-import-helper.h @@ -132,4 +132,6 @@ struct heap_mem *common_dmabuf_heap_rsv_iova_map(struct heap_root *root, int fd, void common_dmabuf_heap_rsv_iova_unmap(struct heap_mem *heap_obj); void common_dmabuf_heap_rsv_iova_uninit(struct heap_root *root); +int remap_malloc_buf(unsigned long addr, size_t len, bool uncaced); + #endif diff --git a/include/uapi/linux/dma_memcp.h b/include/uapi/linux/dma_memcp.h new file mode 100644 index 000000000000..3cb75a348ba8 --- /dev/null +++ b/include/uapi/linux/dma_memcp.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * ESWIN DMA MEMCP Driver + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: Zonglin Geng + * Yuyang Cong + */ + +#ifndef ES_DMA_MEMCP_H +#define ES_DMA_MEMCP_H + +/** + * struct esw_memcp_f2f_cmd - Represents a memory copy command from source to destination. + * + * @src_fd: File descriptor of the source buffer. + * @src_offset: Offset in the source buffer from which data copy starts. + * @dst_fd: File descriptor of the destination buffer. + * @dst_offset: Offset in the destination buffer where data will be copied to. + * @len: Length of the data to be copied, in bytes. + * @timeout: Timeout for the memory copy operation, in milliseconds. + */ +struct esw_memcp_f2f_cmd { + int src_fd; + int src_offset; + int dst_fd; + int dst_offset; + size_t len; + int timeout; +}; + +/** + * struct esw_cmdq_query - Represents the command queue status structure. + * + * @status: Status of the queue, 0 indicates idle, 1 indicates busy. + * @task_count: Current number of tasks in the queue. + */ +struct esw_cmdq_query { + int status; + int task_count; +}; + +#define ESW_MEMCP_MAGIC 'M' +#define ESW_CMDQ_ADD_TASK _IOW(ESW_MEMCP_MAGIC, 1, struct esw_memcp_f2f_cmd) +#define ESW_CMDQ_SYNC _IO(ESW_MEMCP_MAGIC, 2) +#define ESW_CMDQ_QUERY _IOR(ESW_MEMCP_MAGIC, 3, struct esw_cmdq_query) + +#endif diff --git a/sound/soc/codecs/eswin/es8328.c b/sound/soc/codecs/eswin/es8328.c index 29d7c5f0c612..26aedb86a7c9 100644 --- a/sound/soc/codecs/eswin/es8328.c +++ b/sound/soc/codecs/eswin/es8328.c @@ -6,20 +6,24 @@ * * Author: Sean Cross */ - -/* - * Copyright (C) 2021 ESWIN, Inc. All rights reserved. +/***************************************************************************** + * ESWIN codec driver + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. * - * This program is free software; you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation, version 2. * - * 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 for - * more details. + * 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 for more details. * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: DengLei */ @@ -94,8 +98,13 @@ static const char * const supply_names[ES8328_SUPPLY_NUM] = { SNDRV_PCM_FMTBIT_S18_3LE | \ SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ SNDRV_PCM_FMTBIT_S32_LE) +#define EVB_BOARD 1 +#define DVB_BOARD 2 +#define Z530_BOARD 3 + struct es8328_priv { struct regmap *regmap; struct clk *clk; @@ -691,6 +700,10 @@ static const struct snd_soc_dapm_route es8328_dapm_routes[] = { static int es8328_mute(struct snd_soc_dai *dai, int mute, int direction) { + if ((mute == 1) && (direction == 0)) { + snd_soc_component_write(dai->component, ES8328_DACPOWER, 0xc0); + } + return snd_soc_component_update_bits(dai->component, ES8328_DACCONTROL3, ES8328_DACCONTROL3_DACMUTE, mute ? ES8328_DACCONTROL3_DACMUTE : 0); @@ -785,6 +798,13 @@ static int es8328_hw_params(struct snd_pcm_substream *substream, ES8328_ADCCONTROL4_ADCWL_MASK, wl << ES8328_ADCCONTROL4_ADCWL_SHIFT); + if (params_rate(params) <= 48000) { + snd_soc_component_update_bits(component, reg, ES8328_DACCONTROL2_DOUBLESPEED, 0); + } else { + snd_soc_component_update_bits(component, reg, + ES8328_DACCONTROL2_DOUBLESPEED, ES8328_DACCONTROL2_DOUBLESPEED); + } + return snd_soc_component_update_bits(component, reg, ES8328_RATEMASK, ratio); } @@ -894,7 +914,7 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, /* Set MIC PGA Volume */ snd_soc_component_write(component, ES8328_ADCCONTROL1, 0x88); - if (es8328->eswin_plat == 2) { + if (es8328->eswin_plat == DVB_BOARD) { if (gpiod_get_value(es8328->front_jack_gpio) == 1 && gpiod_get_value(es8328->back_jack_gpio) == 0) { /* Select default capture path ---> LIN1 */ snd_soc_component_write(component, ES8328_ADCCONTROL2, 0); @@ -902,6 +922,9 @@ static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, /* Select default capture path ---> LIN2 */ snd_soc_component_write(component, ES8328_ADCCONTROL2, 0x50); } + } else if (es8328->eswin_plat == Z530_BOARD) { + /* Select default capture path ---> LIN1 */ + snd_soc_component_write(component, ES8328_ADCCONTROL2, 0); } else { /* Select default capture path ---> phone mic */ snd_soc_component_write(component, ES8328_ADCCONTROL2, 0xf0); @@ -967,6 +990,7 @@ static int es8328_set_bias_level(struct snd_soc_component *component, 0); break; } + return 0; } @@ -981,7 +1005,7 @@ static const struct snd_soc_dai_ops es8328_dai_ops = { static struct snd_soc_dai_driver es8328_dai[3] = { { - .name = "es8328-0-hifi-analog", + .name = "es8328-0", .playback = { .stream_name = "Playback", .channels_min = MIN_CHANNEL_NUM, @@ -1000,7 +1024,7 @@ static struct snd_soc_dai_driver es8328_dai[3] = { .symmetric_rate = 1, }, { - .name = "es8328-1-hifi-analog", + .name = "es8328-1", .playback = { .stream_name = "Playback", .channels_min = MIN_CHANNEL_NUM, @@ -1019,7 +1043,7 @@ static struct snd_soc_dai_driver es8328_dai[3] = { .symmetric_rate = 1, }, { - .name = "es8328-2-hifi-analog", + .name = "es8328-2", .playback = { .stream_name = "Playback", .channels_min = MIN_CHANNEL_NUM, @@ -1117,6 +1141,7 @@ static int es8328_open(struct snd_soc_component *component, } static const struct snd_soc_component_driver es8328_component_driver = { + .name = "es8388", .probe = es8328_component_probe, .remove = es8328_remove, .suspend = es8328_suspend, @@ -1184,7 +1209,7 @@ int es8328_probe(struct device *dev, struct regmap *regmap) } dev_info(dev, "eswin platform:%d\n", es8328->eswin_plat); - if (es8328->eswin_plat == 2) { + if (es8328->eswin_plat == DVB_BOARD) { es8328->front_jack_gpio = devm_gpiod_get(dev, "front-jack", GPIOD_IN); ret = IS_ERR(es8328->front_jack_gpio); if(ret) { diff --git a/sound/soc/codecs/eswin/es8328.h b/sound/soc/codecs/eswin/es8328.h index 70515466a4b2..fb7068f8f794 100644 --- a/sound/soc/codecs/eswin/es8328.h +++ b/sound/soc/codecs/eswin/es8328.h @@ -2,20 +2,24 @@ /* * es8328.h -- ES8328 ALSA SoC Audio driver */ - -/* - * Copyright (C) 2021 ESWIN, Inc. All rights reserved. +/***************************************************************************** + * ESWIN codec driver * - * This program is free software; you can redistribute it and/or modify + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation, version 2. + * + * 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 for more details. * - * 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 for - * more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * + * Authors: DengLei */ #ifndef _ES8328_H diff --git a/sound/soc/eswin/Kconfig b/sound/soc/eswin/Kconfig index 7c930a329daa..0b25aa84a586 100644 --- a/sound/soc/eswin/Kconfig +++ b/sound/soc/eswin/Kconfig @@ -1,11 +1,8 @@ -menu "SND ESWIN SOC" - +# SPDX-License-Identifier: GPL-2.0-only config SND_ESWIN_DW_I2S tristate "Eswin Dw I2S Device Driver" select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for I2S driver for Eswin dw I2S device. The device supports up to - a maximum of 8 channels each for play and record. - -endmenu + a maximum of 8 channels each for play and record. \ No newline at end of file diff --git a/sound/soc/eswin/Makefile b/sound/soc/eswin/Makefile index 2c133c695dbe..469d77a9732d 100644 --- a/sound/soc/eswin/Makefile +++ b/sound/soc/eswin/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only # ESWIN Platform Support -snd-soc-i2s-objs := esw-i2s.o esw-audio-proc.o +snd-soc-i2s-objs := esw-i2s.o esw-audio-proc.o esw-sof-dai.o esw-dma.o obj-$(CONFIG_SND_ESWIN_DW_I2S) += snd-soc-i2s.o \ No newline at end of file diff --git a/sound/soc/eswin/esw-audio-proc.c b/sound/soc/eswin/esw-audio-proc.c index 17b7c21f7b69..f21e269af657 100644 --- a/sound/soc/eswin/esw-audio-proc.c +++ b/sound/soc/eswin/esw-audio-proc.c @@ -46,9 +46,7 @@ typedef enum AENC_SEND_FRAME, AENC_GET_STREAM, AENC_ENCODE_FRAME, - AGC_PROCESS, - ANS_PROCESS, - AEC_PROCESS, + RTC_PROCESS, //rtc processing for aec, ans, agc DRC_PROCESS, EQ_PROCESS, DCBLOCK_PROCESS, @@ -142,15 +140,15 @@ static void show_ao_data(struct seq_file *m) seq_printf(m, "-----------------------------------------------------------------------------" "-----------------------------------------------------\n"); seq_printf(m, "audio argorithm performance(ns/1ms):\n"); - seq_printf(m, "%-14s%-14s%-14s%-14s%-14s%-14s%-14s%-14s%-14s\n", "agc", "ans", "eq", "hpf", + seq_printf(m, "%-14s%-14s%-14s%-14s%-14s%-14s%-14s%-14s\n", "rtc", "eq", "hpf", "volume", "src-host","src-dai", "host", "dai"); seq_printf(m, "------------------------------------------------------------------------------" "----------------------------------------------------\n"); - seq_printf(m, "%-14d%-14d%-14d%-14d%-14d%-14d%-14d%-14d%-14d\n", g_perf_data[AO][AGC_PROCESS], - g_perf_data[AO][ANS_PROCESS],g_perf_data[AO][EQ_PROCESS], - g_perf_data[AO][DCBLOCK_PROCESS],g_perf_data[AO][VOLUME_PROCESS], - g_perf_data[AO][SRC_HOST_PROCESS],g_perf_data[AO][SRC_DAI_PROCESS], - g_perf_data[AO][HOST_PROCESS], g_perf_data[AO][DAI_PROCESS]); + seq_printf(m, "%-14d%-14d%-14d%-14d%-14d%-14d%-14d%-14d\n", g_perf_data[AO][RTC_PROCESS], + g_perf_data[AO][EQ_PROCESS],g_perf_data[AO][DCBLOCK_PROCESS], + g_perf_data[AO][VOLUME_PROCESS],g_perf_data[AO][SRC_HOST_PROCESS], + g_perf_data[AO][SRC_DAI_PROCESS],g_perf_data[AO][HOST_PROCESS], + g_perf_data[AO][DAI_PROCESS]); seq_printf(m, "\n"); seq_printf(m,"-----------------------------------------------------AO PERF STATISTIC END" "-----------------------------------------------------\n"); @@ -173,14 +171,14 @@ static void show_ai_data(struct seq_file *m) seq_printf(m, "-----------------------------------------------------------------------------" "-----------------------------------------------------\n"); seq_printf(m, "audio argorithm performance(ns/1ms):\n"); - seq_printf(m, "%-14s%-14s%-14s%-14s%-14s%-14s%-14s%-14s%-14s%-14s\n", "agc", "ans", "drc", "eq", + seq_printf(m, "%-14s%-14s%-14s%-14s%-14s%-14s%-14s%-14s%-14s\n", "rtc", "drc", "eq", "hpf", "volume","src-host", "src-dai", "host", "dai"); seq_printf(m, "------------------------------------------------------------------------------" "----------------------------------------------------\n"); - seq_printf(m, "%-14d%-14d%-14d%-14d%-14d%-14d%-14d%-14d%-14d%-14d\n", g_perf_data[AI][AGC_PROCESS], - g_perf_data[AI][ANS_PROCESS],g_perf_data[AI][DRC_PROCESS], g_perf_data[AI][EQ_PROCESS], - g_perf_data[AI][DCBLOCK_PROCESS], g_perf_data[AI][VOLUME_PROCESS],g_perf_data[AI][SRC_HOST_PROCESS], - g_perf_data[AI][SRC_DAI_PROCESS], g_perf_data[AI][HOST_PROCESS], g_perf_data[AI][DAI_PROCESS]); + seq_printf(m, "%-14d%-14d%-14d%-14d%-14d%-14d%-14d%-14d%-14d\n", g_perf_data[AI][RTC_PROCESS], + g_perf_data[AI][DRC_PROCESS], g_perf_data[AI][EQ_PROCESS], g_perf_data[AI][DCBLOCK_PROCESS], + g_perf_data[AI][VOLUME_PROCESS], g_perf_data[AI][SRC_HOST_PROCESS], g_perf_data[AI][SRC_DAI_PROCESS], + g_perf_data[AI][HOST_PROCESS], g_perf_data[AI][DAI_PROCESS]); seq_printf(m, "\n"); seq_printf(m,"-----------------------------------------------------AI PERF STATISTIC END" "-----------------------------------------------------\n"); diff --git a/sound/soc/eswin/esw-dai.h b/sound/soc/eswin/esw-dai.h new file mode 100644 index 000000000000..dfe49c950de0 --- /dev/null +++ b/sound/soc/eswin/esw-dai.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ESWIN audio driver + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: DengLei + */ + +#ifndef __ESWIN_DAI_H__ +#define __ESWIN_DAI_H__ + +#include +#include +#include "esw-i2s.h" + +struct esw_ring_buffer { + uint64_t write; + uint64_t read; + uint64_t buffer_size; +}; + +/* ringbuffer total size 2M + * |<--comp p 512k-->|<--comp c 512k-->|<--pcm p 512k-->|<--pcm c 512k-->| + */ +#define DSP_RB_COMP_SIZE 0x100000 +#define DSP_RB_PCM_P_SZIE 0x80000 +#define DSP_RB_PCM_C_SZIE 0x80000 +#define DSP_RB_POS_SZIE sizeof(struct esw_ring_buffer) +#define DSP_RB_DATA_SZIE (DSP_RB_PCM_P_SZIE - DSP_RB_POS_SZIE) + +#define DSP_RING_BUFFER_IOVA 0xff600000 + +int esw_sof_dma_init(struct i2s_dev *chip); +int esw_sof_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + +int esw_sof_dma_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd); + +int esw_sof_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params); + +int esw_sof_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream); + +int esw_pcm_dma_dai_register(struct i2s_dev *chip); + +#endif \ No newline at end of file diff --git a/sound/soc/eswin/esw-dma.c b/sound/soc/eswin/esw-dma.c new file mode 100644 index 000000000000..387974d16270 --- /dev/null +++ b/sound/soc/eswin/esw-dma.c @@ -0,0 +1,485 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ESWIN audio driver + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: DengLei + */ + +#include +#include +#include +#include +#include "esw-i2s.h" +#include "esw-dai.h" + + +static void esw_pcm_dma_complete(void *arg) +{ + unsigned int new_pos; + struct snd_pcm_substream *substream = arg; + struct i2s_dev *chip = substream->runtime->private_data; + + new_pos = chip->pcm_pos[substream->stream] + snd_pcm_lib_period_bytes(substream); + if (new_pos >= snd_pcm_lib_buffer_bytes(substream)) + new_pos = 0; + chip->pcm_pos[substream->stream] = new_pos; + + snd_pcm_period_elapsed(substream); +} + +static int esw_pcm_dma_prepare_and_submit(struct i2s_dev *chip, + struct snd_pcm_substream *substream) +{ + struct dma_chan *chan = chip->chan[substream->stream]; + struct dma_async_tx_descriptor *desc; + enum dma_transfer_direction direction; + unsigned long flags = DMA_CTRL_ACK; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + direction = DMA_MEM_TO_DEV; + else + direction = DMA_DEV_TO_MEM; + + if (!substream->runtime->no_period_wakeup) + flags |= DMA_PREP_INTERRUPT; + + chip->pcm_pos[substream->stream] = 0; + desc = dmaengine_prep_dma_cyclic(chan, + substream->runtime->dma_addr, + snd_pcm_lib_buffer_bytes(substream) * 64 / substream->runtime->frame_bits, + snd_pcm_lib_period_bytes(substream) * 64 / substream->runtime->frame_bits, + direction, flags); + + if (!desc) + return -ENOMEM; + + desc->callback = esw_pcm_dma_complete; + desc->callback_param = substream; + chip->cookie[substream->stream] = dmaengine_submit(desc); + + return 0; +} + + +int esw_pcm_dma_refine_runtime_hwparams( + struct snd_pcm_substream *substream, + struct snd_pcm_hardware *hw, struct dma_chan *chan) +{ + struct dma_slave_caps dma_caps; + u32 addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); + snd_pcm_format_t i; + int ret = 0; + + if (!hw || !chan) + return -EINVAL; + + ret = dma_get_slave_caps(chan, &dma_caps); + if (ret == 0) { + if (dma_caps.cmd_pause && dma_caps.cmd_resume) + hw->info |= SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME; + if (dma_caps.residue_granularity <= DMA_RESIDUE_GRANULARITY_SEGMENT) + hw->info |= SNDRV_PCM_INFO_BATCH; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + addr_widths = dma_caps.dst_addr_widths; + else + addr_widths = dma_caps.src_addr_widths; + } + + pcm_for_each_format(i) { + int bits = snd_pcm_format_physical_width(i); + + /* + * Enable only samples with DMA supported physical + * widths + */ + switch (bits) { + case 8: + case 16: + case 24: + case 32: + case 64: + if (addr_widths & (1 << (bits / 8))) + hw->formats |= pcm_format_to_bits(i); + break; + default: + /* Unsupported types */ + break; + } + } + + return ret; +} + +int esw_pcm_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct i2s_dev *chip = dev_get_drvdata(component->dev); + struct snd_pcm_hardware hw; + struct dma_chan *chan = chip->chan[substream->stream]; + struct device *dma_dev = chan->device->dev; + struct esw_i2s_dma_data *dma_data; + + dev_dbg(chip->dev, "%s\n", __func__); + + dma_data = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream); + + memset(&hw, 0, sizeof(hw)); + hw.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED; + hw.periods_min = 2; + hw.periods_max = 16; + hw.period_bytes_min = dma_data->max_burst * DMA_SLAVE_BUSWIDTH_8_BYTES; + if (!hw.period_bytes_min) + hw.period_bytes_min = 256; + hw.period_bytes_max = dma_get_max_seg_size(dma_dev); + hw.buffer_bytes_max = hw.period_bytes_max * 16; + hw.fifo_size = dma_data->fifo_size; + hw.info |= SNDRV_PCM_INFO_BATCH; + + esw_pcm_dma_refine_runtime_hwparams(substream, &hw, chan); + + substream->runtime->hw = hw; + substream->runtime->private_data = chip; + + return 0; +} + +static int esw_pcm_dma_prepare_slave_config(struct i2s_dev *chip, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct dma_slave_config *slave_config) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct esw_i2s_dma_data *dma_data; + enum dma_slave_buswidth buswidth; + int bits; + + if (rtd->dai_link->num_cpus > 1) { + dev_err(rtd->dev, + "%s doesn't support Multi CPU yet\n", __func__); + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dma_data = &chip->play_dma_data; + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + dma_data = &chip->capture_dma_data; + + bits = params_physical_width(params); + if (bits < 8 || bits > 64) + return -EINVAL; + else if (bits == 8) + buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; + else if (bits == 16) + buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + else if (bits == 24) + buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES; + else if (bits <= 32) + buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + else + buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config->direction = DMA_MEM_TO_DEV; + slave_config->dst_addr_width = buswidth; + } else { + slave_config->direction = DMA_DEV_TO_MEM; + slave_config->src_addr_width = buswidth; + } + + slave_config->device_fc = false; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config->dst_addr = dma_data->addr; + slave_config->dst_maxburst = dma_data->max_burst; + if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) + slave_config->dst_addr_width = dma_data->addr_width; + } else { + slave_config->src_addr = dma_data->addr; + slave_config->src_maxburst = dma_data->max_burst; + if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) + slave_config->src_addr_width = dma_data->addr_width; + } + + return 0; +} + +int esw_pcm_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct i2s_dev *chip = dev_get_drvdata(component->dev); + struct dma_slave_config slave_config; + int ret; + + dev_dbg(chip->dev, "%s, period size:%d, period cnt:%d\n", __func__, + params_period_size(params), params_periods(params)); + + memset(&slave_config, 0, sizeof(slave_config)); + + ret = esw_pcm_dma_prepare_slave_config(chip, substream, params, &slave_config); + if (ret) + return ret; + + ret = dmaengine_slave_config(chip->chan[substream->stream], &slave_config); + if (ret) + return ret; + + return 0; +} + +int esw_pcm_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct i2s_dev *chip = dev_get_drvdata(component->dev); + + dev_dbg(chip->dev, "%s\n", __func__); + + dmaengine_synchronize(chip->chan[substream->stream]); + + return 0; +} + +int esw_pcm_dma_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + struct i2s_dev *chip = dev_get_drvdata(component->dev); + struct snd_pcm_runtime *runtime = substream->runtime; + struct dma_chan *chan = chip->chan[substream->stream]; + int ret; + + dev_dbg(chip->dev, "%s, cmd:%d, sample bits:%d\n", __func__, cmd, runtime->sample_bits); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + ret = esw_pcm_dma_prepare_and_submit(chip, substream); + if (ret) { + dev_err(chip->dev, "dma prepare and submit error\n"); + return ret; + } + dma_async_issue_pending(chan); + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + dmaengine_resume(chan); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + if (runtime->info & SNDRV_PCM_INFO_PAUSE) + dmaengine_pause(chan); + else + dmaengine_terminate_async(chan); + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + dmaengine_pause(chan); + break; + case SNDRV_PCM_TRIGGER_STOP: + dmaengine_terminate_async(chan); + break; + default: + return -EINVAL; + } + + return 0; +} + +snd_pcm_uframes_t esw_pcm_dma_pointer(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct i2s_dev *chip = substream->runtime->private_data; + return bytes_to_frames(substream->runtime, chip->pcm_pos[substream->stream]); +} + +static int esw_pcm_dma_process(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + int channel, unsigned long hwoff, + struct iov_iter *iter, unsigned long bytes) +{ + struct i2s_dev *chip = container_of(component, struct i2s_dev, pcm_component); + struct snd_pcm_runtime *runtime = substream->runtime; + bool is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + char *dma_ptr = (char *)runtime->dma_area + hwoff * 64 / runtime->frame_bits + + channel * (runtime->dma_bytes / runtime->channels); + snd_pcm_uframes_t frames; + u16 *ptr_16; + u8 *ptr_24_raw; + u32 *ptr_24; + u32 *ptr_32; + int i; + + if (is_playback) { + if (runtime->sample_bits == 32) { + if (copy_from_iter(dma_ptr, bytes, iter) != bytes) + return -EFAULT; + } else { + if (copy_from_iter(chip->conv_buf[0], bytes, iter) != bytes) + return -EFAULT; + if (runtime->sample_bits == 16) { + ptr_16 = (u16 *)chip->conv_buf[0]; + ptr_32 = (u32 *)dma_ptr; + frames = bytes_to_frames(runtime, bytes); + for (i = 0; i < 2 * frames; i++) { + ptr_32[i] = (u32)ptr_16[i]; + } + } else if (runtime->sample_bits == 24) { + ptr_24_raw = (u8 *)chip->conv_buf[0]; + ptr_32 = (u32 *)dma_ptr; + for (i = 0; i < bytes / 3; i++) { + ptr_24 = (u32 *)(ptr_24_raw + i * 3); + ptr_32[i] = (*ptr_24) & 0xffffff; + } + } + } + } else { + if (runtime->sample_bits == 32) { + if (copy_to_iter(dma_ptr, bytes, iter) != bytes) + return -EFAULT; + } else { + if (runtime->sample_bits == 16) { + frames = bytes_to_frames(runtime, bytes); + ptr_16 = (u16 *)chip->conv_buf[1]; + ptr_32 = (u32 *)dma_ptr; + for (i = 0; i < 2 * frames; i++) { + ptr_16[i] = ptr_32[i]; + } + } else if (runtime->sample_bits == 24) { + ptr_24_raw = (u8 *)chip->conv_buf[1]; + ptr_32 = (u32 *)dma_ptr; + for (i = 0; i < bytes / 3; i++) { + memcpy(&ptr_24_raw[i * 3], &ptr_32[i], 3); + } + } + if (copy_to_iter(chip->conv_buf[1], bytes, iter) != bytes) + return -EFAULT; + } + } + + return 0; +} + +static int esw_pcm_dma_new(struct snd_soc_component *component, + struct snd_soc_pcm_runtime *rtd) +{ + struct i2s_dev *chip = container_of(component, struct i2s_dev, pcm_component); + size_t prealloc_buffer_size; + size_t max_buffer_size; + unsigned int i; + + prealloc_buffer_size = 512 * 1024; + max_buffer_size = SIZE_MAX; + + for_each_pcm_streams(i) { + struct snd_pcm_substream *substream = rtd->pcm->streams[i].substream; + if (!substream) + continue; + + snd_pcm_set_managed_buffer(substream, + SNDRV_DMA_TYPE_DEV_IRAM, + chip->chan[substream->stream]->device->dev, + prealloc_buffer_size, + max_buffer_size); + } + + return 0; +} + +static const struct snd_soc_component_driver esw_pcm_component_driver = { + .name = "esw-dma", + .probe_order = SND_SOC_COMP_ORDER_LATE, + .open = esw_pcm_dma_open, + .close = esw_pcm_dma_close, + .hw_params = esw_pcm_dma_hw_params, + .trigger = esw_pcm_dma_trigger, + .pointer = esw_pcm_dma_pointer, + .copy = esw_pcm_dma_process, + .pcm_construct = esw_pcm_dma_new, +}; + +int esw_pcm_dma_dai_register(struct i2s_dev *chip) +{ + struct dma_chan *chan0; + struct dma_chan *chan1; + const char *channel_names0 = "tx"; + const char *channel_names1 = "rx"; + int ret; + u32 period_bytes_max; + + dev_dbg(chip->dev, "%s\n", __func__); + + chan0 = dma_request_chan(chip->dev, channel_names0); + if (IS_ERR(chan0)) { + if (PTR_ERR(chan0) == -EPROBE_DEFER) { + dev_err(chip->dev, "request dma channel[%s] failed\n", channel_names0); + return -EPROBE_DEFER; + } + dev_err(chip->dev, "dma channel[%s] is NULL\n", channel_names0); + } else { + chip->chan[SNDRV_PCM_STREAM_PLAYBACK] = chan0; + period_bytes_max = dma_get_max_seg_size(chan0->device->dev); + chip->conv_buf[SNDRV_PCM_STREAM_PLAYBACK] = kzalloc(period_bytes_max, GFP_KERNEL); + if (!chip->conv_buf[SNDRV_PCM_STREAM_PLAYBACK]) { + ret = -ENOMEM; + dev_err(chip->dev, "alloc conv buf0 err:%d\n", ret); + goto release_chan0; + } + } + + chan1 = dma_request_chan(chip->dev, channel_names1); + if (IS_ERR(chan1)) { + if (PTR_ERR(chan1) == -EPROBE_DEFER) { + dev_err(chip->dev, "request dma channel[%s] failed\n", channel_names1); + ret = -EPROBE_DEFER; + goto release_buf0; + } + dev_err(chip->dev, "dma channel[%s] is NULL\n", channel_names1); + } else { + chip->chan[SNDRV_PCM_STREAM_CAPTURE] = chan1; + period_bytes_max = dma_get_max_seg_size(chan1->device->dev); + chip->conv_buf[SNDRV_PCM_STREAM_CAPTURE] = kzalloc(period_bytes_max, GFP_KERNEL); + if (!chip->conv_buf[SNDRV_PCM_STREAM_CAPTURE]) { + dev_err(chip->dev, "alloc conv buf0 err:%d\n", ret); + ret = -ENOMEM; + goto release_chan1; + } + } + + ret = snd_soc_component_initialize(&chip->pcm_component, &esw_pcm_component_driver, chip->dev); + if (ret) + goto release_buf1; + + ret = snd_soc_add_component(&chip->pcm_component, NULL, 0); + if (ret) { + dev_err(chip->dev, "add pcm component failed\n"); + goto release_buf1; + } + + return 0; + +release_buf1: + kfree(chip->conv_buf[1]); +release_chan1: + dma_release_channel(chip->chan[1]); +release_buf0: + kfree(chip->conv_buf[0]); +release_chan0: + dma_release_channel(chip->chan[0]); + + return ret; +} \ No newline at end of file diff --git a/sound/soc/eswin/esw-i2s.c b/sound/soc/eswin/esw-i2s.c index efae45ee2f31..0d40aee31f87 100755 --- a/sound/soc/eswin/esw-i2s.c +++ b/sound/soc/eswin/esw-i2s.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ALSA SoC Synopsys I2S Audio Layer * @@ -11,20 +12,24 @@ * warranty of any kind, whether express or implied. * */ - -/* - * Copyright (C) 2021 ESWIN, Inc. All rights reserved. +/***************************************************************************** + * ESWIN i2s driver * - * This program is free software; you can redistribute it and/or modify + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation, version 2. + * + * 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 for more details. * - * 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 for - * more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * + * Authors: DengLei */ #include @@ -50,8 +55,10 @@ #include #include #include +#include #include "esw-i2s.h" #include "esw-audio-proc.h" +#include "esw-dai.h" #define VO_MCLK_DIVSOR_MASK 0xff0 #define VO_MCLK_DIVSOR_OFFSET 4 @@ -69,10 +76,14 @@ #define ESW_I2S_RATES (SNDRV_PCM_RATE_192000 | \ SNDRV_PCM_RATE_96000 | \ SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_44100 | \ SNDRV_PCM_RATE_32000 | \ SNDRV_PCM_RATE_16000 | \ SNDRV_PCM_RATE_8000) -#define ESW_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE) +#define ESW_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE) #define DIE0_I2S0_IO_ADDR 0x51600124 #define DIE1_I2S0_IO_ADDR 0x71600124 @@ -80,9 +91,14 @@ #define DIE0_DAI_DRIVER_OFFSET 0 #define DIE1_DAI_DRIVER_OFFSET 4 -#define HDMI_DAI_NAME "i2s0-hdmi" +#define APLL_HIGH_FREQ 983040000 +#define APLL_LOW_FREQ 225792000 -static struct clk *g_mclk; +#define D0_HDMI_DAI_NAME "i2s0-hdmi" +#define D1_HDMI_DAI_NAME "d1-i2s0-hdmi" + +static int enable_441k[2] = {0, 0}; +static int i2s_enable_cnt[2] = {0, 0}; static u32 dmaen_txch[] = { DMAEN_TXCH_0, @@ -129,35 +145,39 @@ int i2s_get_nid(struct device *dev) return nid; } -static int set_mclk(struct device *dev, struct clk **i2s_clk) +static int set_mclk(struct device *dev, struct i2s_dev *i2s_drvdata) { - const char *clk_id = "mclk"; - struct clk *clk = NULL; int ret; - clk = devm_clk_get(dev, clk_id); - if (IS_ERR(clk)) { - dev_err(dev, "Failed to get clock: %ld\n", PTR_ERR(clk)); - return PTR_ERR(clk); + i2s_drvdata->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(i2s_drvdata->mclk)) { + dev_err(dev, "Failed to get mclock: %ld\n", PTR_ERR(i2s_drvdata->mclk)); + return PTR_ERR(i2s_drvdata->mclk); } - ret = clk_prepare_enable(clk); + ret = clk_prepare_enable(i2s_drvdata->mclk); if (ret < 0) { - dev_err(dev, "Failed to enable clock: %d\n", ret); + dev_err(dev, "Failed to enable mclock: %d\n", ret); return ret; } /* only set once */ if (of_node_name_prefix(dev->of_node, "i2s0")) { - ret = clk_set_rate(clk, MAX_SAMPLE_RATE_CLK); + ret = clk_set_rate(i2s_drvdata->mclk, MAX_SAMPLE_RATE_CLK); if (ret) { - dev_err(dev, "Can't set I2S clock rate: %d\n", ret); - clk_disable_unprepare(clk); + dev_err(dev, "Can't set I2S mclock rate: %d\n", ret); + clk_disable_unprepare(i2s_drvdata->mclk); return ret; } } - *i2s_clk = clk; + i2s_drvdata->apll_clk = devm_clk_get(dev, "apll"); + if (IS_ERR(i2s_drvdata->apll_clk)) { + dev_err(dev, "Failed to get apll clock: %ld\n", PTR_ERR(i2s_drvdata->apll_clk)); + clk_disable_unprepare(i2s_drvdata->mclk); + return PTR_ERR(i2s_drvdata->apll_clk); + } + return 0; } @@ -360,8 +380,6 @@ static void i2s_stop(struct i2s_dev *i2s_drvdata, static int i2s_configure_res_by_dt(struct i2s_dev *dev, struct resource *res) { - struct snd_soc_component *component; - struct dmaengine_pcm *pcm; u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1); u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2); u32 fifo_depth; @@ -386,13 +404,6 @@ static int i2s_configure_res_by_dt(struct i2s_dev *dev, } dev->fifo_th = fifo_depth / 2; - component = snd_soc_lookup_component(dev->dev, SND_DMAENGINE_PCM_DRV_NAME); - if (!component) { - dev_err(dev->dev, "Can not find snd_soc_component\n"); - return -1; - } - - pcm = soc_component_to_pcm(component); if (COMP1_TX_ENABLED(comp1)) { idx2 = COMP1_TX_WORDSIZE_0(comp1); dev->capability |= DWC_I2S_PLAY; @@ -401,7 +412,7 @@ static int i2s_configure_res_by_dt(struct i2s_dev *dev, dev->play_dma_data.fifo_size = fifo_depth * (fifo_width[idx2]) >> 3; dev->play_dma_data.addr = res->start + TXDMA_CH(0); - dev->play_dma_data.maxburst = 16; + dev->play_dma_data.max_burst = 16; } if (COMP1_RX_ENABLED(comp1)) { idx2 = COMP2_RX_WORDSIZE_0(comp2); @@ -411,8 +422,9 @@ static int i2s_configure_res_by_dt(struct i2s_dev *dev, dev->capture_dma_data.fifo_size = fifo_depth * (fifo_width[idx2]) >> 3; dev->capture_dma_data.addr = res->start + RXDMA_CH(0); - dev->capture_dma_data.maxburst = 16; + dev->capture_dma_data.max_burst = 16; } + return 0; } @@ -424,10 +436,6 @@ static int i2s_startup(struct snd_pcm_substream *substream, dai_link->trigger_stop = SND_SOC_TRIGGER_ORDER_LDC; - if (!strcmp(cpu_dai->name, HDMI_DAI_NAME)) { - dai_link->playback_only = 1; - } - return 0; } @@ -438,6 +446,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, struct i2s_clk_config_data *config = &i2s_drvdata->config; uint32_t div_num = 0; uint32_t div_num_reg; + int ret; dev_dbg(i2s_drvdata->dev, "sample rate:%d, chan:%d, width:%d\n", params_rate(params), params_channels(params), params_width(params)); @@ -449,6 +458,7 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, i2s_drvdata->xfer_resolution = RESOLUTION_16_BIT; break; case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S24_3LE: config->data_width = 24; i2s_drvdata->ccr = CLOCK_CYCLES_32 << CCR_WSS_POS | NO_CLOCK_GATING; @@ -476,25 +486,74 @@ static int i2s_hw_params(struct snd_pcm_substream *substream, i2s_write_reg(i2s_drvdata->i2s_base, CCR, i2s_drvdata->ccr); config->sample_rate = params_rate(params); if (i2s_drvdata->capability & DW_I2S_MASTER) { - if (MAX_SAMPLE_RATE_SUPPORT % config->sample_rate != 0) { - dev_err(i2s_drvdata->dev, "Not support sample rate: %d\n", config->sample_rate); - return -EINVAL; - } - - div_num = MAX_SAMPLE_RATE_SUPPORT / config->sample_rate - 1; - - if (i2s_drvdata->active) { - if (i2s_drvdata->i2s_div_num != div_num) { - dev_err(i2s_drvdata->dev, "Not support the playback and capture clocks are different\n"); - return -EINVAL; + if (config->sample_rate == 44100) { + if (!enable_441k[i2s_drvdata->nid]) { + if (!i2s_enable_cnt[i2s_drvdata->nid]) { + ret = clk_set_rate(i2s_drvdata->mclk, MAX_SAMPLE_RATE_CLK * 2); + if (ret) { + dev_err(i2s_drvdata->dev, "Can't set I2S mclock rate: %d\n", ret); + return ret; + } + ret = clk_set_rate(i2s_drvdata->apll_clk, APLL_LOW_FREQ); + if (ret) { + dev_err(i2s_drvdata->dev, "Can't set I2S apll clock rate: %d\n", ret); + return ret; + } + enable_441k[i2s_drvdata->nid] = 1; + div_num_reg = i2s_read_reg(i2s_drvdata->i2s_div_base, 0) & ~DIV_NUM_MASK; + div_num_reg |= 1; + i2s_write_reg(i2s_drvdata->i2s_div_base, 0, div_num_reg); + i2s_drvdata->i2s_div_num = 1; + dev_dbg(i2s_drvdata->dev, "apll rate:%ld\n", clk_get_rate(i2s_drvdata->apll_clk)); + } else { + dev_err(i2s_drvdata->dev, "Other sample rate audio is playing.\n"); + return -EINVAL; + } + } else { + div_num_reg = i2s_read_reg(i2s_drvdata->i2s_div_base, 0) & ~DIV_NUM_MASK; + div_num_reg |= 1; + i2s_write_reg(i2s_drvdata->i2s_div_base, 0, div_num_reg); + i2s_drvdata->i2s_div_num = 1; } } else { - div_num_reg = i2s_read_reg(i2s_drvdata->i2s_div_base, 0) & ~DIV_NUM_MASK; - div_num_reg |= div_num; + if (enable_441k[i2s_drvdata->nid]) { + if (!i2s_enable_cnt[i2s_drvdata->nid]) { + ret = clk_set_rate(i2s_drvdata->apll_clk, APLL_HIGH_FREQ); + if (ret) { + dev_err(i2s_drvdata->dev, "Can't set I2S apll clock rate: %d\n", ret); + return ret; + } + ret = clk_set_rate(i2s_drvdata->mclk, MAX_SAMPLE_RATE_CLK); + if (ret) { + dev_err(i2s_drvdata->dev, "Can't set I2S mclock rate: %d\n", ret); + return ret; + } + enable_441k[i2s_drvdata->nid] = 0; + dev_dbg(i2s_drvdata->dev, "apll rate:%ld\n", clk_get_rate(i2s_drvdata->apll_clk)); + } else { + dev_err(i2s_drvdata->dev, "44.1khz audio is playing.\n"); + return -EINVAL; + } + } + if (MAX_SAMPLE_RATE_SUPPORT % config->sample_rate != 0) { + dev_err(i2s_drvdata->dev, "Not support sample rate: %d\n", config->sample_rate); + return -EINVAL; + } - dev_dbg(i2s_drvdata->dev, "div num:0x%x\n", div_num); - i2s_drvdata->i2s_div_num = div_num; - i2s_write_reg(i2s_drvdata->i2s_div_base, 0, div_num_reg); + div_num = MAX_SAMPLE_RATE_SUPPORT / config->sample_rate - 1; + + if (i2s_drvdata->active) { + if (i2s_drvdata->i2s_div_num != div_num) { + dev_err(i2s_drvdata->dev, "Not support the playback and capture clocks are different\n"); + return -EINVAL; + } + } else { + div_num_reg = i2s_read_reg(i2s_drvdata->i2s_div_base, 0) & ~DIV_NUM_MASK; + div_num_reg |= div_num; + dev_dbg(i2s_drvdata->dev, "div num:0x%x\n", div_num); + i2s_drvdata->i2s_div_num = div_num; + i2s_write_reg(i2s_drvdata->i2s_div_base, 0, div_num_reg); + } } } @@ -518,6 +577,8 @@ static int i2s_trigger(struct snd_pcm_substream *substream, { struct i2s_dev *i2s_drvdata = snd_soc_dai_get_drvdata(dai); int ret = 0; + + dev_dbg(i2s_drvdata->dev, "%s\n", __func__); switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -529,6 +590,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream, } else { i2s_drvdata->capture_active = true; } + i2s_enable_cnt[i2s_drvdata->nid]++; break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: @@ -540,6 +602,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream, } else { i2s_drvdata->capture_active = false; } + i2s_enable_cnt[i2s_drvdata->nid]--; break; default: ret = -EINVAL; @@ -598,7 +661,7 @@ static const struct snd_soc_dai_ops i2s_dai_ops = { static int i2s_runtime_suspend(struct device *dev) { struct i2s_dev *i2s_drvdata = dev_get_drvdata(dev); - struct clk *clk = i2s_drvdata->clk; + struct clk *clk = i2s_drvdata->mclk; dev_dbg(i2s_drvdata->dev, "%s\n", __func__); @@ -610,7 +673,7 @@ static int i2s_runtime_suspend(struct device *dev) static int i2s_runtime_resume(struct device *dev) { struct i2s_dev *i2s_drvdata = dev_get_drvdata(dev); - struct clk *clk = i2s_drvdata->clk; + struct clk *clk = i2s_drvdata->mclk; dev_dbg(i2s_drvdata->dev, "%s\n", __func__); clk_enable(clk); @@ -621,7 +684,7 @@ static int i2s_runtime_resume(struct device *dev) static int i2s_suspend(struct snd_soc_component *component) { struct i2s_dev *i2s_drvdata = snd_soc_component_get_drvdata(component); - struct clk *clk = i2s_drvdata->clk; + struct clk *clk = i2s_drvdata->mclk; dev_dbg(i2s_drvdata->dev, "%s\n", __func__); if(!pm_runtime_suspended(i2s_drvdata->dev)) { @@ -636,7 +699,7 @@ static int i2s_resume(struct snd_soc_component *component) { struct i2s_dev *i2s_drvdata = snd_soc_component_get_drvdata(component); struct snd_soc_dai *dai = NULL; - struct clk *clk = i2s_drvdata->clk; + struct clk *clk = i2s_drvdata->mclk; int stream; dev_dbg(i2s_drvdata->dev, "%s\n", __func__); @@ -662,7 +725,8 @@ static int i2s_reset(struct platform_device *pdev, struct i2s_dev *i2s) struct reset_control *rst; struct reset_control *prst; struct reset_control *voprst; - int ret; + void __iomem *i2s0_io_base; + int ret, reg_val; rst = devm_reset_control_get_optional_exclusive(&pdev->dev, "i2srst"); if (IS_ERR(rst)) { @@ -690,6 +754,32 @@ static int i2s_reset(struct platform_device *pdev, struct i2s_dev *i2s) ret = reset_control_deassert(voprst); WARN_ON(0 != ret); + if (!of_property_read_bool(pdev->dev.of_node, "io_reuse_enable")) { + i2s0_io_base = devm_ioremap(&pdev->dev, DIE0_I2S0_IO_ADDR, 12); + if (!i2s0_io_base) { + dev_err(&pdev->dev, "failed to remap i2s0 io ctl\n"); + return -ENOMEM; + } + + /* set the i2s0 WCLK io to GPIO func */ + reg_val = readl((char *)i2s0_io_base); + reg_val &= 0xfff8ffff; + reg_val |= 0x20000; + writel(reg_val, (char *)i2s0_io_base); + + /* set the i2s0 SDI io to GPIO func */ + reg_val = readl((char *)i2s0_io_base + 4); + reg_val &= 0xfff8ffff; + reg_val |= 0x20000; + writel(reg_val, (char *)i2s0_io_base + 4); + + /* set the i2s0 SDO io to GPIO func */ + reg_val = readl((char *)i2s0_io_base + 8); + reg_val &= 0xfff8ffff; + reg_val |= 0x20000; + writel(reg_val, (char *)i2s0_io_base + 8); + } + return 0; } @@ -708,15 +798,21 @@ static int i2s_open(struct snd_soc_component *component, } static const struct snd_soc_component_driver i2s_component = { - .name = "i2s0", .open = i2s_open, .suspend = i2s_suspend, .resume = i2s_resume, }; +static const struct snd_soc_component_driver i2s_sof_component = { + .open = esw_sof_dma_open, + .close = esw_sof_dma_close, + .hw_params = esw_sof_dma_hw_params, + .trigger = esw_sof_dma_trigger, +}; + static struct snd_soc_dai_driver i2s_dai[8] = { { - .name = HDMI_DAI_NAME, + .name = D0_HDMI_DAI_NAME, .id = 0, .ops = &i2s_dai_ops, .playback = { @@ -751,14 +847,12 @@ static struct snd_soc_dai_driver i2s_dai[8] = { .id = 0, .ops = &i2s_dai_ops, .playback = { - .stream_name = "Playback", .channels_min = MIN_CHANNEL_NUM, .channels_max = MAX_CHANNEL_NUM, .rates = ESW_I2S_RATES, .formats = ESW_I2S_FORMATS, }, .capture = { - .stream_name = "Capture", .channels_min = MIN_CHANNEL_NUM, .channels_max = MAX_CHANNEL_NUM, .rates = ESW_I2S_RATES, @@ -770,14 +864,12 @@ static struct snd_soc_dai_driver i2s_dai[8] = { .id = 0, .ops = &i2s_dai_ops, .playback = { - .stream_name = "Playback", .channels_min = MIN_CHANNEL_NUM, .channels_max = MAX_CHANNEL_NUM, .rates = ESW_I2S_RATES, .formats = ESW_I2S_FORMATS, }, .capture = { - .stream_name = "Capture", .channels_min = MIN_CHANNEL_NUM, .channels_max = MAX_CHANNEL_NUM, .rates = ESW_I2S_RATES, @@ -785,18 +877,10 @@ static struct snd_soc_dai_driver i2s_dai[8] = { }, }, { - .name = "d1-i2s0-hdmi", + .name = D1_HDMI_DAI_NAME, .id = 0, .ops = &i2s_dai_ops, .playback = { - .stream_name = "Playback", - .channels_min = MIN_CHANNEL_NUM, - .channels_max = MAX_CHANNEL_NUM, - .rates = ESW_I2S_RATES, - .formats = ESW_I2S_FORMATS, - }, - .capture = { - .stream_name = "Capture", .channels_min = MIN_CHANNEL_NUM, .channels_max = MAX_CHANNEL_NUM, .rates = ESW_I2S_RATES, @@ -808,14 +892,12 @@ static struct snd_soc_dai_driver i2s_dai[8] = { .id = 1, .ops = &i2s_dai_ops, .playback = { - .stream_name = "Playback", .channels_min = MIN_CHANNEL_NUM, .channels_max = MAX_CHANNEL_NUM, .rates = ESW_I2S_RATES, .formats = ESW_I2S_FORMATS, }, .capture = { - .stream_name = "Capture", .channels_min = MIN_CHANNEL_NUM, .channels_max = MAX_CHANNEL_NUM, .rates = ESW_I2S_RATES, @@ -827,14 +909,12 @@ static struct snd_soc_dai_driver i2s_dai[8] = { .id = 0, .ops = &i2s_dai_ops, .playback = { - .stream_name = "Playback", .channels_min = MIN_CHANNEL_NUM, .channels_max = MAX_CHANNEL_NUM, .rates = ESW_I2S_RATES, .formats = ESW_I2S_FORMATS, }, .capture = { - .stream_name = "Capture", .channels_min = MIN_CHANNEL_NUM, .channels_max = MAX_CHANNEL_NUM, .rates = ESW_I2S_RATES, @@ -846,14 +926,12 @@ static struct snd_soc_dai_driver i2s_dai[8] = { .id = 0, .ops = &i2s_dai_ops, .playback = { - .stream_name = "Playback", .channels_min = MIN_CHANNEL_NUM, .channels_max = MAX_CHANNEL_NUM, .rates = ESW_I2S_RATES, .formats = ESW_I2S_FORMATS, }, .capture = { - .stream_name = "Capture", .channels_min = MIN_CHANNEL_NUM, .channels_max = MAX_CHANNEL_NUM, .rates = ESW_I2S_RATES, @@ -862,6 +940,65 @@ static struct snd_soc_dai_driver i2s_dai[8] = { }, }; +static int i2s_sof_ringbuffer_init(struct i2s_dev *i2s_drvdata) +{ + struct resource res_sram; + int ret; + struct device_node *rb_node; + u32 ringbuffer_in_addr; + u32 ringbuffer_out_addr; + + rb_node = of_parse_phandle(i2s_drvdata->dev->of_node, "ringbuffer-region", 0); + if (IS_ERR(rb_node)) { + dev_err(i2s_drvdata->dev, "Get phandle dsp-sram error\n"); + return -ENODEV; + } + of_node_put(i2s_drvdata->dev->of_node); + + ret = of_address_to_resource(rb_node, 0, &res_sram); + if (ret) { + dev_err(i2s_drvdata->dev, "failed to get ring buffer address\n"); + return ret; + } + of_node_put(rb_node); + + ringbuffer_in_addr = res_sram.start + DSP_RB_COMP_SIZE + DSP_RB_PCM_P_SZIE; + ringbuffer_out_addr = res_sram.start + DSP_RB_COMP_SIZE; + + i2s_drvdata->pos[0] = devm_ioremap(i2s_drvdata->dev, ringbuffer_out_addr, DSP_RB_PCM_C_SZIE + DSP_RB_PCM_P_SZIE); + if(!i2s_drvdata->pos[0]) { + dev_err(i2s_drvdata->dev, "failed to remap stream out pos\n"); + return -ENOMEM; + } + i2s_drvdata->pos[1] = i2s_drvdata->pos[0] + DSP_RB_PCM_P_SZIE; + + memset(i2s_drvdata->pos[0], 0, (DSP_RB_PCM_P_SZIE + DSP_RB_PCM_C_SZIE)); + + i2s_drvdata->rb_out_iova = dma_map_page_attrs(i2s_drvdata->chan[0]->device->dev, + phys_to_page(ringbuffer_out_addr + DSP_RB_POS_SZIE), + offset_in_page(ringbuffer_out_addr + DSP_RB_POS_SZIE), + DSP_RB_DATA_SZIE, DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(i2s_drvdata->chan[0]->device->dev, i2s_drvdata->rb_out_iova)) { + dev_err(i2s_drvdata->dev, "dma mapping failed\n"); + return -ENOMEM; + } + dev_dbg(i2s_drvdata->dev, "rb out iova_addr:0x%llx\n", i2s_drvdata->rb_out_iova); + + i2s_drvdata->rb_in_iova = dma_map_page_attrs(i2s_drvdata->chan[1]->device->dev, + phys_to_page(ringbuffer_in_addr + DSP_RB_POS_SZIE), + offset_in_page(ringbuffer_in_addr + DSP_RB_POS_SZIE), + DSP_RB_DATA_SZIE, DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(i2s_drvdata->chan[1]->device->dev, i2s_drvdata->rb_in_iova)) { + dev_err(i2s_drvdata->dev, "dma mapping failed\n"); + dma_unmap_page_attrs(i2s_drvdata->chan[0]->device->dev, i2s_drvdata->rb_out_iova, DSP_RB_DATA_SZIE, + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); + return -ENOMEM; + } + dev_dbg(i2s_drvdata->dev, "rb in iova_addr:0x%llx\n", i2s_drvdata->rb_in_iova); + + return 0; +} + static int i2s_probe(struct platform_device *pdev) { struct i2s_dev *i2s_drvdata; @@ -869,25 +1006,13 @@ static int i2s_probe(struct platform_device *pdev) int ret = 0; int nid = 0; unsigned long vo_top_csr; - unsigned long i2s0_io_addr; int dai_offset = 0; - struct snd_dmaengine_pcm_config *config; - void __iomem *i2s0_io_base; - int reg_val; dev_info(&pdev->dev, "dev name:%s\n", pdev->dev.of_node->name); i2s_drvdata = devm_kzalloc(&pdev->dev, sizeof(*i2s_drvdata), GFP_KERNEL); if (!i2s_drvdata) return -ENOMEM; - config = devm_kzalloc(&pdev->dev, - sizeof(struct snd_dmaengine_pcm_config), GFP_KERNEL); - if (!config) - return -ENOMEM; - config->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = "tx"; - config->chan_names[SNDRV_PCM_STREAM_CAPTURE] = "rx"; - config->prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; - res = platform_get_resource(pdev,IORESOURCE_MEM, 0); i2s_drvdata->i2s_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(i2s_drvdata->i2s_base)) { @@ -905,8 +1030,9 @@ static int i2s_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s:%d, NUMA_NO_NODE\n", __func__, __LINE__); return -EFAULT; } + i2s_drvdata->nid = nid; - ret = set_mclk(&pdev->dev, &i2s_drvdata->clk); + ret = set_mclk(&pdev->dev, i2s_drvdata); if (ret < 0) { return ret; } @@ -917,33 +1043,6 @@ static int i2s_probe(struct platform_device *pdev) dev_err(&pdev->dev, "i2s_reset failed\n"); goto err_probe; } - - if (!of_property_read_bool(pdev->dev.of_node, "io_reuse_enable")) { - i2s0_io_addr = get_i2s0_io_addr(nid); - i2s0_io_base = devm_ioremap(&pdev->dev, i2s0_io_addr, 12); - if (!i2s0_io_base) { - dev_err(i2s_drvdata->dev, "failed to remap i2s0 io ctl\n"); - return -ENOMEM; - } - - /* set the i2s0 WCLK io to GPIO func */ - reg_val = readl((char *)i2s0_io_base); - reg_val &= 0xfff8ffff; - reg_val |= 0x20000; - writel(reg_val, (char *)i2s0_io_base); - - /* set the i2s0 SDI io to GPIO func */ - reg_val = readl((char *)i2s0_io_base + 4); - reg_val &= 0xfff8ffff; - reg_val |= 0x20000; - writel(reg_val, (char *)i2s0_io_base + 4); - - /* set the i2s0 SDO io to GPIO func */ - reg_val = readl((char *)i2s0_io_base + 8); - reg_val &= 0xfff8ffff; - reg_val |= 0x20000; - writel(reg_val, (char *)i2s0_io_base + 8); - } } dev_set_drvdata(&pdev->dev, i2s_drvdata); @@ -956,7 +1055,11 @@ static int i2s_probe(struct platform_device *pdev) ret = -ENOMEM; goto err_probe; } - ret = devm_snd_soc_register_component(&pdev->dev, &i2s_component, &i2s_dai[dai_offset], 2); + if (of_property_read_bool(pdev->dev.of_node, "dsp_sof_enable")) { + ret = devm_snd_soc_register_component(&pdev->dev, &i2s_sof_component, &i2s_dai[dai_offset], 2); + } else { + ret = devm_snd_soc_register_component(&pdev->dev, &i2s_component, &i2s_dai[dai_offset], 2); + } } else if (of_node_name_prefix(pdev->dev.of_node, "i2s1")) { i2s_drvdata->i2s_div_base = devm_ioremap(i2s_drvdata->dev, vo_top_csr + VO_I2S1_DIV_NUM, 4); if (!i2s_drvdata->i2s_div_base) { @@ -964,7 +1067,11 @@ static int i2s_probe(struct platform_device *pdev) ret = -ENOMEM; goto err_probe; } - ret = devm_snd_soc_register_component(&pdev->dev, &i2s_component, &i2s_dai[2 + dai_offset], 1); + if (of_property_read_bool(pdev->dev.of_node, "dsp_sof_enable")) { + ret = devm_snd_soc_register_component(&pdev->dev, &i2s_sof_component, &i2s_dai[2 + dai_offset], 1); + } else { + ret = devm_snd_soc_register_component(&pdev->dev, &i2s_component, &i2s_dai[2 + dai_offset], 1); + } } else { i2s_drvdata->i2s_div_base = devm_ioremap(i2s_drvdata->dev, vo_top_csr + VO_I2S2_DIV_NUM, 4); if (!i2s_drvdata->i2s_div_base) { @@ -972,7 +1079,11 @@ static int i2s_probe(struct platform_device *pdev) ret = -ENOMEM; goto err_probe; } - ret = devm_snd_soc_register_component(&pdev->dev, &i2s_component, &i2s_dai[3 + dai_offset], 1); + if (of_property_read_bool(pdev->dev.of_node, "dsp_sof_enable")) { + ret = devm_snd_soc_register_component(&pdev->dev, &i2s_sof_component, &i2s_dai[3 + dai_offset], 1); + } else { + ret = devm_snd_soc_register_component(&pdev->dev, &i2s_component, &i2s_dai[3 + dai_offset], 1); + } } if (ret != 0) { dev_err(&pdev->dev, "not able to register dai\n"); @@ -980,10 +1091,24 @@ static int i2s_probe(struct platform_device *pdev) } i2s_drvdata->use_pio = false; - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, config, 0); - if (ret) { - dev_err(&pdev->dev, "could not register pcm: %d\n", ret); - goto err_probe; + + if (of_property_read_bool(pdev->dev.of_node, "dsp_sof_enable")) { + ret = esw_sof_dma_init(i2s_drvdata); + if (ret != 0) { + dev_err(&pdev->dev, "pcm dma init failed\n"); + goto err_probe; + } + ret = i2s_sof_ringbuffer_init(i2s_drvdata); + if (ret != 0) { + dev_err(&pdev->dev, "pcm ringbuffer init failed\n"); + goto err_probe; + } + } else { + ret = esw_pcm_dma_dai_register(i2s_drvdata); + if (ret) { + dev_err(&pdev->dev, "could not register pcm: %d\n", ret); + goto err_probe; + } } i2s_drvdata->i2s_reg_comp1 = I2S_COMP_PARAM_1; @@ -999,11 +1124,11 @@ static int i2s_probe(struct platform_device *pdev) audio_proc_module_init(); #ifdef CONFIG_PM - clk_disable(i2s_drvdata->clk); + clk_disable(i2s_drvdata->mclk); #endif return 0; err_probe: - clk_disable_unprepare(i2s_drvdata->clk); + clk_disable_unprepare(i2s_drvdata->mclk); return ret; } @@ -1012,12 +1137,22 @@ static int i2s_remove(struct platform_device *pdev) { struct i2s_dev *i2s_drvdata = dev_get_drvdata(&pdev->dev); - clk_disable_unprepare(i2s_drvdata->clk); + dev_info(&pdev->dev, "dev name:%s\n", pdev->dev.of_node->name); + clk_disable_unprepare(i2s_drvdata->mclk); pm_runtime_disable(&pdev->dev); - audio_proc_module_exit(); + if (of_property_read_bool(pdev->dev.of_node, "dsp_sof_enable")) { + dma_unmap_page_attrs(i2s_drvdata->chan[0]->device->dev, i2s_drvdata->rb_out_iova, DSP_RB_DATA_SZIE, + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); + dma_unmap_page_attrs(i2s_drvdata->chan[1]->device->dev, i2s_drvdata->rb_in_iova, DSP_RB_DATA_SZIE, + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); + } else { + kfree(i2s_drvdata->conv_buf[0]); + kfree(i2s_drvdata->conv_buf[1]); + } + return 0; } @@ -1038,7 +1173,7 @@ static struct platform_driver i2s_driver = { .probe = i2s_probe, .remove = i2s_remove, .driver = { - .name = "i2s", + .name = "es-i2s", .of_match_table = of_match_ptr(i2s_of_match), .pm = &i2s_pm_ops, }, diff --git a/sound/soc/eswin/esw-i2s.h b/sound/soc/eswin/esw-i2s.h index 6c1a243223a4..63f12992236f 100644 --- a/sound/soc/eswin/esw-i2s.h +++ b/sound/soc/eswin/esw-i2s.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (ST) 2012 Rajeev Kumar (rajeevkumar.linux@gmail.com) * @@ -5,21 +6,24 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. */ - -/* +/***************************************************************************** + * ESWIN i2s driver * - * Copyright (C) 2021 ESWIN, Inc. All rights reserved. + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. * - * This program is free software; you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * the Free Software Foundation, version 2. * - * 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 for - * more details. + * 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 for more details. * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: DengLei */ #ifndef __I2S_H @@ -32,7 +36,6 @@ #include #include #include -#include #include @@ -145,9 +148,20 @@ enum { RESOLUTION_32_BIT }; + +struct esw_i2s_dma_data { + void *data; + dma_addr_t addr; + u32 max_burst; + unsigned int fifo_size; + enum dma_slave_buswidth addr_width; + bool (*filter)(struct dma_chan *chan, void *slave); +}; + struct i2s_dev { void __iomem *i2s_base; - struct clk *clk; + struct clk *mclk; + struct clk *apll_clk; struct device *dev; unsigned int i2s_reg_comp1; unsigned int i2s_reg_comp2; @@ -155,8 +169,8 @@ struct i2s_dev { u32 fifo_th; bool use_pio; /* data related to DMA transfers b/w i2s and DMAC */ - struct snd_dmaengine_dai_dma_data play_dma_data; - struct snd_dmaengine_dai_dma_data capture_dma_data; + struct esw_i2s_dma_data play_dma_data; + struct esw_i2s_dma_data capture_dma_data; struct i2s_clk_config_data config; struct snd_pcm_substream __rcu *tx_substream; struct snd_pcm_substream __rcu *rx_substream; @@ -175,6 +189,17 @@ struct i2s_dev { u32 i2s_div_num; bool playback_active; bool capture_active; + int nid; + + struct dma_chan *chan[2]; + dma_cookie_t cookie[2]; + void *pos[2]; + dma_addr_t rb_in_iova; + dma_addr_t rb_out_iova; + + unsigned int pcm_pos[2]; + struct snd_soc_component pcm_component; + void *conv_buf[2]; }; #endif /* __I2S_H */ diff --git a/sound/soc/eswin/esw-sof-dai.c b/sound/soc/eswin/esw-sof-dai.c new file mode 100644 index 000000000000..214487ec1d44 --- /dev/null +++ b/sound/soc/eswin/esw-sof-dai.c @@ -0,0 +1,299 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ESWIN audio driver + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: DengLei + */ + +#include +#include +#include +#include +#include "esw-dai.h" + +static void esw_sof_dma_tx_callback(void *arg) +{ + struct i2s_dev *chip = arg; + struct esw_ring_buffer *rb = (struct esw_ring_buffer *)chip->pos[0]; + struct snd_pcm_substream *substream = chip->tx_substream; + int count = 0; + + if (!rb) { + dev_err(chip->dev, "pos addr is NULL\n"); + return; + } + + while(1) { + if (rb->read + snd_pcm_lib_period_bytes(substream) <= rb->write) { + rb->read += snd_pcm_lib_period_bytes(substream); + dev_dbg(chip->dev, "read pos:%lld, write pos:%lld, buffer size:%lld\n", + rb->read, rb->write, rb->buffer_size); + break; + } + if (count++ == 10000) { + dev_warn(chip->dev, "dsp update pos timeout, read pos:%lld, write pos:%lld, buffer size:%lld\n", + rb->read, rb->write, rb->buffer_size); + break; + } + } +} + +static void esw_sof_dma_rx_callback(void *arg) +{ + struct i2s_dev *chip = arg; + struct esw_ring_buffer *rb = (struct esw_ring_buffer *)chip->pos[1]; + struct snd_pcm_substream *substream = chip->rx_substream; + + if (!rb) { + dev_err(chip->dev, "pos addr is NULL\n"); + return; + } + + rb->write += snd_pcm_lib_period_bytes(substream); + dev_dbg(chip->dev, "read pos:%lld, write pos:%lld, buffer size:%lld\n", + rb->read, rb->write, rb->buffer_size); +} + +static int esw_sof_dma_prepare_and_submit(struct i2s_dev *chip, + struct snd_pcm_substream *substream) +{ + struct dma_chan *chan = chip->chan[substream->stream]; + struct dma_async_tx_descriptor *desc; + enum dma_transfer_direction direction; + unsigned long flags = DMA_CTRL_ACK; + dma_addr_t dma_addr; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + direction = DMA_MEM_TO_DEV; + dma_addr = chip->rb_out_iova; + } else { + direction = DMA_DEV_TO_MEM; + dma_addr = chip->rb_in_iova; + } + + if (!substream->runtime->no_period_wakeup) + flags |= DMA_PREP_INTERRUPT; + + desc = dmaengine_prep_dma_cyclic(chan, dma_addr, + snd_pcm_lib_buffer_bytes(substream), + snd_pcm_lib_period_bytes(substream), + direction, flags); + + if (!desc) + return -ENOMEM; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + desc->callback = esw_sof_dma_tx_callback; + } else { + desc->callback = esw_sof_dma_rx_callback; + } + + desc->callback_param = chip; + chip->cookie[substream->stream] = dmaengine_submit(desc); + + return 0; +} + +int esw_sof_dma_open(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct i2s_dev *chip = dev_get_drvdata(component->dev); + struct dma_chan *chan = chip->chan[substream->stream]; + + if (!chan) { + dev_err(component->dev, "%s dma channel is null\n", __func__); + return -ENXIO; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + chip->tx_substream = substream; + memset(chip->pos[0], 0, 8); + } else { + chip->rx_substream = substream; + memset(chip->pos[1], 0, 8); + } + + return 0; +} + +static int esw_sof_dma_prepare_slave_config(struct i2s_dev *chip, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct dma_slave_config *slave_config) +{ + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); + struct esw_i2s_dma_data *dma_data; + enum dma_slave_buswidth buswidth; + int bits; + + if (rtd->dai_link->num_cpus > 1) { + dev_err(rtd->dev, + "%s doesn't support Multi CPU yet\n", __func__); + return -EINVAL; + } + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + dma_data = &chip->play_dma_data; + else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + dma_data = &chip->capture_dma_data; + + bits = params_physical_width(params); + if (bits < 8 || bits > 64) + return -EINVAL; + else if (bits == 8) + buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; + else if (bits == 16) + buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + else if (bits == 24) + buswidth = DMA_SLAVE_BUSWIDTH_3_BYTES; + else if (bits <= 32) + buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; + else + buswidth = DMA_SLAVE_BUSWIDTH_8_BYTES; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config->direction = DMA_MEM_TO_DEV; + slave_config->dst_addr_width = buswidth; + } else { + slave_config->direction = DMA_DEV_TO_MEM; + slave_config->src_addr_width = buswidth; + } + + slave_config->device_fc = false; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config->dst_addr = dma_data->addr; + slave_config->dst_maxburst = dma_data->max_burst; + if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) + slave_config->dst_addr_width = dma_data->addr_width; + } else { + slave_config->src_addr = dma_data->addr; + slave_config->src_maxburst = dma_data->max_burst; + if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED) + slave_config->src_addr_width = dma_data->addr_width; + } + + return 0; +} + +int esw_sof_dma_hw_params(struct snd_soc_component *component, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct i2s_dev *chip = dev_get_drvdata(component->dev); + struct dma_slave_config slave_config; + int ret; + + dev_dbg(chip->dev, "%s\n", __func__); + + memset(&slave_config, 0, sizeof(slave_config)); + + ret = esw_sof_dma_prepare_slave_config(chip, substream, params, &slave_config); + if (ret) + return ret; + + ret = dmaengine_slave_config(chip->chan[substream->stream], &slave_config); + if (ret) + return ret; + + return 0; +} + +int esw_sof_dma_close(struct snd_soc_component *component, + struct snd_pcm_substream *substream) +{ + struct i2s_dev *chip = dev_get_drvdata(component->dev); + + dmaengine_synchronize(chip->chan[substream->stream]); + return 0; +} + +int esw_sof_dma_trigger(struct snd_soc_component *component, + struct snd_pcm_substream *substream, int cmd) +{ + struct i2s_dev *chip = dev_get_drvdata(component->dev); + struct snd_pcm_runtime *runtime = substream->runtime; + struct dma_chan *chan = chip->chan[substream->stream]; + int ret; + + dev_dbg(chip->dev, "%s, cmd:%d\n", __func__, cmd); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + ret = esw_sof_dma_prepare_and_submit(chip, substream); + if (ret) { + dev_err(chip->dev, "dma prepare and submit error\n"); + return ret; + } + dma_async_issue_pending(chan); + break; + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + dmaengine_resume(chan); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + if (runtime->info & SNDRV_PCM_INFO_PAUSE) + dmaengine_pause(chan); + else + dmaengine_terminate_async(chan); + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + dmaengine_pause(chan); + break; + case SNDRV_PCM_TRIGGER_STOP: + dmaengine_terminate_async(chan); + break; + default: + return -EINVAL; + } + + return 0; +} + +int esw_sof_dma_init(struct i2s_dev *chip) +{ + struct dma_chan *chan0; + struct dma_chan *chan1; + const char *channel_names0 = "rx"; + const char *channel_names1 = "tx"; + + dev_dbg(chip->dev, "%s\n", __func__); + + chan0 = dma_request_chan(chip->dev, channel_names0); + if (IS_ERR(chan0)) { + if (PTR_ERR(chan0) == -EPROBE_DEFER) { + dev_err(chip->dev, "request dma channel[%d] failed\n", SNDRV_PCM_STREAM_CAPTURE); + return -EPROBE_DEFER; + } + dev_err(chip->dev, "dma channel[%d] is NULL\n", SNDRV_PCM_STREAM_CAPTURE); + } else { + chip->chan[SNDRV_PCM_STREAM_CAPTURE] = chan0; + } + + chan1 = dma_request_chan(chip->dev, channel_names1); + if (IS_ERR(chan1)) { + if (PTR_ERR(chan1) == -EPROBE_DEFER) { + dev_err(chip->dev, "request dma channel[%d] failed\n", SNDRV_PCM_STREAM_PLAYBACK); + return -EPROBE_DEFER; + } + dev_err(chip->dev, "dma channel[%d] is NULL\n", SNDRV_PCM_STREAM_PLAYBACK); + } else { + chip->chan[SNDRV_PCM_STREAM_PLAYBACK] = chan1; + } + + return 0; +} \ No newline at end of file diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig index 80361139a49a..92e66354e117 100644 --- a/sound/soc/sof/Kconfig +++ b/sound/soc/sof/Kconfig @@ -291,5 +291,6 @@ source "sound/soc/sof/imx/Kconfig" source "sound/soc/sof/intel/Kconfig" source "sound/soc/sof/mediatek/Kconfig" source "sound/soc/sof/xtensa/Kconfig" +source "sound/soc/sof/eswin/Kconfig" endif diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index 744d40bd8c8b..df2cbbd9dbb0 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -58,3 +58,4 @@ obj-$(CONFIG_SND_SOC_SOF_IMX_TOPLEVEL) += imx/ obj-$(CONFIG_SND_SOC_SOF_AMD_TOPLEVEL) += amd/ obj-$(CONFIG_SND_SOC_SOF_XTENSA) += xtensa/ obj-$(CONFIG_SND_SOC_SOF_MTK_TOPLEVEL) += mediatek/ +obj-$(CONFIG_SND_SOC_SOF_ESWIN_TOPLEVEL) += eswin/ \ No newline at end of file diff --git a/sound/soc/sof/eswin/Kconfig b/sound/soc/sof/eswin/Kconfig new file mode 100644 index 000000000000..273e28dcb67b --- /dev/null +++ b/sound/soc/sof/eswin/Kconfig @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) + +config SND_SOC_SOF_ESWIN_TOPLEVEL + bool "SOF support for ESWIN win2030 audio DSPs" + depends on SND_SOC_SOF_OF + default n + help + This adds support for Sound Open Firmware for ESWIN win2030 platforms. + Say Y if you have such a device. + If unsure select "N". + +if SND_SOC_SOF_ESWIN_TOPLEVEL + +config SND_SOC_SOF_ESWIN_COMMON + bool + select SND_SOC_SOF_OF_DEV + select SND_SOC_SOF + select SND_SOC_SOF_IPC3 + select SND_SOC_SOF_XTENSA + select SND_SOC_SOF_COMPRESS + help + This option is not user-selectable but automagically handled by + 'select' statements at a higher level. + +config SND_SOC_SOF_ESWIN + tristate "SOF support for eswin" + select SND_SOC_SOF_ESWIN_COMMON + default n + help + This adds support for Sound Open Firmware for ESWIN win2030 platforms. + Say Y if you have such a device. + If unsure select "N". + +endif ## SND_SOC_SOF_ESWIN_TOPLEVEL diff --git a/sound/soc/sof/eswin/Makefile b/sound/soc/sof/eswin/Makefile new file mode 100644 index 000000000000..dcb9c540b37b --- /dev/null +++ b/sound/soc/sof/eswin/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +ccflags-y += -I$(srctree)/drivers/soc/eswin/ + +snd-sof-eswin-dsp-objs := es-sof-dsp.o es-common.o + +obj-$(CONFIG_SND_SOC_SOF_ESWIN) += snd-sof-eswin-dsp.o diff --git a/sound/soc/sof/eswin/es-common.c b/sound/soc/sof/eswin/es-common.c new file mode 100644 index 000000000000..22228f4b840e --- /dev/null +++ b/sound/soc/sof/eswin/es-common.c @@ -0,0 +1,591 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ESWIN audio sof driver + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: DengLei + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "../ops.h" + +#include "es-common.h" + +#define DSP_SUBSYS_HILOAD_CLK 1040000000 //1G +#define DSP_SUBSYS_LOWLOAD_CLK 5200000 +struct xtensa_exception_cause { + u32 id; + const char *msg; + const char *description; +}; + +/* + * From 4.4.1.5 table 4-64 Exception Causes of Xtensa + * Instruction Set Architecture (ISA) Reference Manual + */ +static const struct xtensa_exception_cause xtensa_exception_causes[] = { + {0, "IllegalInstructionCause", "Illegal instruction"}, + {1, "SyscallCause", "SYSCALL instruction"}, + {2, "InstructionFetchErrorCause", + "Processor internal physical address or data error during instruction fetch"}, + {3, "LoadStoreErrorCause", + "Processor internal physical address or data error during load or store"}, + {4, "Level1InterruptCause", + "Level-1 interrupt as indicated by set level-1 bits in the INTERRUPT register"}, + {5, "AllocaCause", + "MOVSP instruction, if caller’s registers are not in the register file"}, + {6, "IntegerDivideByZeroCause", + "QUOS, QUOU, REMS, or REMU divisor operand is zero"}, + {8, "PrivilegedCause", + "Attempt to execute a privileged operation when CRING ? 0"}, + {9, "LoadStoreAlignmentCause", "Load or store to an unaligned address"}, + {12, "InstrPIFDataErrorCause", + "PIF data error during instruction fetch"}, + {13, "LoadStorePIFDataErrorCause", + "Synchronous PIF data error during LoadStore access"}, + {14, "InstrPIFAddrErrorCause", + "PIF address error during instruction fetch"}, + {15, "LoadStorePIFAddrErrorCause", + "Synchronous PIF address error during LoadStore access"}, + {16, "InstTLBMissCause", "Error during Instruction TLB refill"}, + {17, "InstTLBMultiHitCause", + "Multiple instruction TLB entries matched"}, + {18, "InstFetchPrivilegeCause", + "An instruction fetch referenced a virtual address at a ring level less than CRING"}, + {20, "InstFetchProhibitedCause", + "An instruction fetch referenced a page mapped with an attribute that does not permit instruction fetch"}, + {24, "LoadStoreTLBMissCause", + "Error during TLB refill for a load or store"}, + {25, "LoadStoreTLBMultiHitCause", + "Multiple TLB entries matched for a load or store"}, + {26, "LoadStorePrivilegeCause", + "A load or store referenced a virtual address at a ring level less than CRING"}, + {28, "LoadProhibitedCause", + "A load referenced a page mapped with an attribute that does not permit loads"}, + {32, "Coprocessor0Disabled", + "Coprocessor 0 instruction when cp0 disabled"}, + {33, "Coprocessor1Disabled", + "Coprocessor 1 instruction when cp1 disabled"}, + {34, "Coprocessor2Disabled", + "Coprocessor 2 instruction when cp2 disabled"}, + {35, "Coprocessor3Disabled", + "Coprocessor 3 instruction when cp3 disabled"}, + {36, "Coprocessor4Disabled", + "Coprocessor 4 instruction when cp4 disabled"}, + {37, "Coprocessor5Disabled", + "Coprocessor 5 instruction when cp5 disabled"}, + {38, "Coprocessor6Disabled", + "Coprocessor 6 instruction when cp6 disabled"}, + {39, "Coprocessor7Disabled", + "Coprocessor 7 instruction when cp7 disabled"}, +}; + +/* only need xtensa atm */ +static void xtensa_dsp_oops(struct snd_sof_dev *sdev, const char *level, void *oops) +{ + struct sof_ipc_dsp_oops_xtensa *xoops = oops; + int i; + + dev_printk(level, sdev->dev, "error: DSP Firmware Oops\n"); + for (i = 0; i < ARRAY_SIZE(xtensa_exception_causes); i++) { + if (xtensa_exception_causes[i].id == xoops->exccause) { + dev_printk(level, sdev->dev, + "error: Exception Cause: %s, %s\n", + xtensa_exception_causes[i].msg, + xtensa_exception_causes[i].description); + } + } + dev_printk(level, sdev->dev, + "EXCCAUSE 0x%8.8x EXCVADDR 0x%8.8x PS 0x%8.8x SAR 0x%8.8x\n", + xoops->exccause, xoops->excvaddr, xoops->ps, xoops->sar); + dev_printk(level, sdev->dev, + "EPC1 0x%8.8x EPC2 0x%8.8x EPC3 0x%8.8x EPC4 0x%8.8x", + xoops->epc1, xoops->epc2, xoops->epc3, xoops->epc4); + dev_printk(level, sdev->dev, + "EPC5 0x%8.8x EPC6 0x%8.8x EPC7 0x%8.8x DEPC 0x%8.8x", + xoops->epc5, xoops->epc6, xoops->epc7, xoops->depc); + dev_printk(level, sdev->dev, + "EPS2 0x%8.8x EPS3 0x%8.8x EPS4 0x%8.8x EPS5 0x%8.8x", + xoops->eps2, xoops->eps3, xoops->eps4, xoops->eps5); + dev_printk(level, sdev->dev, + "EPS6 0x%8.8x EPS7 0x%8.8x INTENABL 0x%8.8x INTERRU 0x%8.8x", + xoops->eps6, xoops->eps7, xoops->intenable, xoops->interrupt); +} + +static void xtensa_stack(struct snd_sof_dev *sdev, const char *level, void *oops, + u32 *stack, u32 stack_words) +{ + struct sof_ipc_dsp_oops_xtensa *xoops = oops; + u32 stack_ptr = xoops->plat_hdr.stackptr; + /* 4 * 8chars + 3 ws + 1 terminating NUL */ + unsigned char buf[4 * 8 + 3 + 1]; + int i; + + dev_printk(level, sdev->dev, "stack dump from 0x%8.8x\n", stack_ptr); + + /* + * example output: + * 0x0049fbb0: 8000f2d0 0049fc00 6f6c6c61 00632e63 + */ + for (i = 0; i < stack_words; i += 4) { + hex_dump_to_buffer(stack + i, 16, 16, 4, + buf, sizeof(buf), false); + dev_printk(level, sdev->dev, "0x%08x: %s\n", stack_ptr + i * 4, buf); + } +} + +const struct dsp_arch_ops es_sof_xtensa_arch_ops = { + .dsp_oops = xtensa_dsp_oops, + .dsp_stack = xtensa_stack, +}; + +/** + * eswin_get_registers() - This function is called in case of DSP oops + * in order to gather information about the registers, filename and + * linenumber and stack. + * @sdev: SOF device + * @xoops: Stores information about registers. + * @panic_info: Stores information about filename and line number. + * @stack: Stores the stack dump. + * @stack_words: Size of the stack dump. + */ +static void eswin_dsp_get_registers(struct snd_sof_dev *sdev, + struct sof_ipc_dsp_oops_xtensa *xoops, + struct sof_ipc_panic_info *panic_info, + u32 *stack, size_t stack_words) +{ + u32 offset = sdev->dsp_oops_offset; + + /* first read registers */ + sof_mailbox_read(sdev, offset, xoops, sizeof(*xoops)); + + /* then get panic info */ + if (xoops->arch_hdr.totalsize > EXCEPT_MAX_HDR_SIZE) { + dev_err(sdev->dev, "invalid header size 0x%x. FW oops is bogus\n", + xoops->arch_hdr.totalsize); + return; + } + offset += xoops->arch_hdr.totalsize; + sof_mailbox_read(sdev, offset, panic_info, sizeof(*panic_info)); + + /* then get the stack */ + offset += sizeof(*panic_info); + sof_mailbox_read(sdev, offset, stack, stack_words * sizeof(u32)); +} + +/** + * es_dsp_dump() - This function is called when a panic message is + * received from the firmware. + * @sdev: SOF device + * @flags: parameter not used but required by ops prototype + */ +void es_dsp_dump(struct snd_sof_dev *sdev, u32 flags) +{ + struct sof_ipc_dsp_oops_xtensa xoops; + struct sof_ipc_panic_info panic_info; + u32 stack[ESWIN_DSP_STACK_DUMP_SIZE]; + u32 status; + + /* Get information about the panic status from the debug box area. + * Compute the trace point based on the status. + */ + sof_mailbox_read(sdev, sdev->debug_box.offset + 0x4, &status, 4); + + /* Get information about the registers, the filename and line + * number and the stack. + */ + eswin_dsp_get_registers(sdev, &xoops, &panic_info, stack, + ESWIN_DSP_STACK_DUMP_SIZE); + + /* Print the information to the console */ + sof_print_oops_and_stack(sdev, KERN_ERR, status, status, &xoops, + &panic_info, stack, ESWIN_DSP_STACK_DUMP_SIZE); +} + +int es_dsp_ring_doorbell(struct es_dsp_ipc *ipc, void *msg) +{ + int ret; + struct es_dsp_chan *dsp_chan; + + dsp_chan = &ipc->chan; + ret = mbox_send_message(dsp_chan->ch, msg); + if (ret < 0) + return ret; + + return 0; +} + +static void es_dsp_handle_rx(struct mbox_client *c, void *msg) +{ + struct es_dsp_chan *chan = container_of(c, struct es_dsp_chan, cl); + u32 dsp_msg = *(u32 *)msg; + + if (dsp_msg == IPC_MSG_RP_FLAG) { + chan->ipc->ops->handle_reply(chan->ipc); + } else { + chan->ipc->ops->handle_request(chan->ipc); + } +} + +static void es_dsp_tx_done(struct mbox_client *cl, void *mssg, int r) +{ + if (mssg) + kfree(mssg); +} + +struct mbox_chan *es_dsp_request_channel(struct es_dsp_ipc *dsp_ipc) +{ + struct es_dsp_chan *dsp_chan; + + dsp_chan = &dsp_ipc->chan; + dsp_chan->ch = mbox_request_channel_byname(&dsp_chan->cl, dsp_chan->name); + return dsp_chan->ch; +} + +void es_dsp_free_channel(struct es_dsp_ipc *dsp_ipc) +{ + struct es_dsp_chan *dsp_chan; + + dsp_chan = &dsp_ipc->chan; + mbox_free_channel(dsp_chan->ch); +} + +static int es_dsp_setup_channels(struct es_dsp_ipc *dsp_ipc) +{ + struct device *dev = dsp_ipc->dev; + struct es_dsp_chan *dsp_chan; + struct mbox_client *cl; + char *chan_name; + int ret; + + chan_name = "dsp-mbox"; + + dsp_chan = &dsp_ipc->chan; + dsp_chan->name = chan_name; + cl = &dsp_chan->cl; + cl->dev = dev; + cl->tx_block = false; + cl->knows_txdone = false; + cl->rx_callback = es_dsp_handle_rx; + cl->tx_done = es_dsp_tx_done; + + dsp_chan->ipc = dsp_ipc; + dsp_chan->ch = mbox_request_channel_byname(cl, chan_name); + if (IS_ERR(dsp_chan->ch)) { + ret = PTR_ERR(dsp_chan->ch); + dev_err(dev, "Failed to request mbox chan %s ret %d\n", chan_name, ret); + return ret; + } + + dev_info(dev, "request mbox chan %s\n", chan_name); + + return 0; +} + +struct es_dsp_ipc *es_ipc_init(struct snd_sof_dev *sdev) +{ + struct es_dsp_ipc *dsp_ipc; + int ret; + + dsp_ipc = devm_kzalloc(sdev->dev, sizeof(*dsp_ipc), GFP_KERNEL); + if (!dsp_ipc) + return NULL; + + dsp_ipc->dev = sdev->dev; + + ret = es_dsp_setup_channels(dsp_ipc); + if (ret < 0) + return NULL; + + dev_info(sdev->dev, "ESW DSP IPC initialized\n"); + + return dsp_ipc; +} + +int es_get_hw_res(struct snd_sof_dev *sdev) +{ + struct es_sof_priv *priv = (struct es_sof_priv *)sdev->pdata->hw_pdata; + struct device_node *nd; + struct resource res; + int ret; + + ret = of_address_to_resource(sdev->dev->of_node, 0, &res); + if (ret) { + dev_err(sdev->dev, "failed to get dsp iram address\n"); + return ret; + } + of_node_put(sdev->dev->of_node); + priv->dsp_iram_phyaddr = res.start; + priv->dsp_iram_size = resource_size(&res); + + + ret = of_address_to_resource(sdev->dev->of_node, 1, &res); + if (ret) { + dev_err(sdev->dev, "failed to get dsp dram address\n"); + return ret; + } + of_node_put(sdev->dev->of_node); + priv->dsp_dram_phyaddr = res.start; + priv->dsp_dram_size = resource_size(&res); + + ret = device_property_read_u32(sdev->dev, "process-id", &(priv->process_id)); + if (0 != ret) { + dev_err(sdev->dev, "Failed to get process id\n"); + return ret; + } + + ret = device_property_read_u32(sdev->dev, "mailbox-dsp-to-u84-addr", &priv->mbox_rx_phyaddr); + if (0 != ret) { + dev_err(sdev->dev, "failed to get mailbox rx addr\n"); + return ret; + } + + ret = device_property_read_u32(sdev->dev, "mailbox-u84-to-dsp-addr", &priv->mbox_tx_phyaddr); + if (0 != ret) { + dev_err(sdev->dev, "failed to get mailbox tx addr\n"); + return ret; + } + + /* get aclk */ + priv->aclk = devm_clk_get(sdev->dev, "aclk"); + if (IS_ERR(priv->aclk)) { + ret = PTR_ERR(priv->aclk); + dev_err(sdev->dev, "failed to get aclk: %d\n", ret); + return ret; + } + + nd = of_parse_phandle(sdev->dev->of_node, "dsp-uart", 0); + if (!nd) { + dev_err(sdev->dev, "failed to get uart node\n"); + return -ENODEV; + } + of_node_put(sdev->dev->of_node); + + ret = of_address_to_resource(nd, 0, &res); + if (ret) { + dev_err(sdev->dev, "failed to get dsp uart address\n"); + return ret; + } + of_node_put(nd); + priv->uart_phyaddr = res.start; + priv->uart_reg_size = resource_size(&res); + + ret = device_property_read_u32(sdev->dev, "device-uart-mutex", &priv->uart_mutex_phyaddr); + if (0 != ret) { + dev_err(sdev->dev, "Failed to get uart mutex reg base\n"); + return ret; + } + + nd = of_parse_phandle(sdev->dev->of_node, "ringbuffer-region", 0); + if (!nd) { + dev_err(sdev->dev, "failed to get ringbuffer region node\n"); + return -ENODEV; + } + of_node_put(sdev->dev->of_node); + + ret = of_address_to_resource(nd, 0, &res); + if (ret) { + dev_err(sdev->dev, "failed to get ring buffer address\n"); + return ret; + } + of_node_put(nd); + + priv->ringbuffer_phyaddr = res.start; + priv->ringbuffer_size = resource_size(&res); + + return ret; +} + +int es_dsp_get_subsys(struct snd_sof_dev *sdev) +{ + struct device *parent; + struct es_dsp_subsys *subsys; + struct es_sof_priv *priv = (struct es_sof_priv *)sdev->pdata->hw_pdata; + + parent = priv->dev->parent; + subsys = dev_get_drvdata(parent); + if (IS_ERR_OR_NULL(subsys)) { + return -EPROBE_DEFER; + } + if (!try_module_get(subsys->pdev->dev.driver->owner)) { + dev_err(sdev->dev, "error try get dsp subsys module.\n"); + return -EIO; + } + + get_device(&subsys->pdev->dev); + priv->dsp_subsys = subsys; + return 0; +} + +void es_dsp_put_subsys(struct snd_sof_dev *sdev) +{ + struct es_dsp_subsys *subsys; + struct es_sof_priv *priv = (struct es_sof_priv *)sdev->pdata->hw_pdata; + + subsys = priv->dsp_subsys; + put_device(&subsys->pdev->dev); + module_put(subsys->pdev->dev.driver->owner); + return; +} + +static int es_dsp_set_rate(struct es_sof_priv *priv, unsigned long rate) +{ + int ret; + + rate = clk_round_rate(priv->aclk, rate); + if (rate > 0) { + ret = clk_set_rate(priv->aclk, rate); + if (ret) { + dev_err(priv->dev, "failed to set aclk: %d\n", ret); + return ret; + } + } + dev_info(priv->dev, "set device rate to %ldHZ\n", rate); + return 0; +} + +int es_dsp_hw_init(struct snd_sof_dev *sdev) +{ + int ret; + struct es_sof_priv *priv = (struct es_sof_priv *)sdev->pdata->hw_pdata; + + ret = iommu_map_rsv_iova_with_phys(sdev->dev, + (dma_addr_t)DSP_UART_IOVA, + priv->uart_reg_size, + priv->uart_phyaddr, IOMMU_MMIO); + if (ret != 0) { + dev_err(sdev->dev, "uart iommu map error\n"); + return ret; + } + priv->uart_dev_addr = DSP_UART_IOVA; + + ret = iommu_map_rsv_iova_with_phys( + sdev->dev, (dma_addr_t)DSP_UART_MUTEX_IOVA, + DSP_UART_MUTEX_IOVA_SIZE, priv->uart_mutex_phyaddr, + IOMMU_MMIO); + if (ret != 0) { + dev_err(sdev->dev, "uart mutex iommu map error\n"); + ret = -ENOMEM; + goto err_map_uart; + } + priv->uart_mutex_dev_addr = DSP_UART_MUTEX_IOVA; + + ret = iommu_map_rsv_iova_with_phys(sdev->dev, + (dma_addr_t)DSP_MBOX_TX_IOVA, + DSP_MBOX_IOVA_SIZE, + priv->mbox_tx_phyaddr, IOMMU_MMIO); + if (ret != 0) { + dev_err(sdev->dev, "mailbox tx iommu map error\n"); + ret = -ENOMEM; + goto err_map_uart_mutex; + } + priv->mbox_tx_dev_addr = DSP_MBOX_TX_IOVA; + + ret = iommu_map_rsv_iova_with_phys(sdev->dev, + (dma_addr_t)DSP_MBOX_RX_IOVA, + DSP_MBOX_IOVA_SIZE, + priv->mbox_rx_phyaddr, IOMMU_MMIO); + if (ret != 0) { + dev_err(sdev->dev, "mailbox rx iommu map error\n"); + ret = -ENOMEM; + goto err_map_mbox_tx; + } + priv->mbox_rx_dev_addr = DSP_MBOX_RX_IOVA; + + priv->firmware_addr = + iommu_map_rsv_iova(sdev->dev, (dma_addr_t)DSP_FIRMWARE_IOVA, + DSP_FIRMWARE_IOVA_SIZE, GFP_KERNEL, 0); + if (IS_ERR_OR_NULL(priv->firmware_addr)) { + dev_err(sdev->dev, "failed to alloc firmware memory\n"); + ret = -ENOMEM; + goto err_map_mbox_rx; + } + priv->firmware_dev_addr = DSP_FIRMWARE_IOVA; + sdev->bar[SOF_FW_BLK_TYPE_SRAM] = priv->firmware_addr; + + ret = iommu_map_rsv_iova_with_phys(sdev->dev, (dma_addr_t)DSP_RING_BUFFER_IOVA, + priv->ringbuffer_size, priv->ringbuffer_phyaddr, IOMMU_MMIO); + if (ret != 0) { + dev_err(sdev->dev, "failed to map ringbuffer memory\n"); + ret = -ENOMEM; + goto err_map_fw; + } + priv->ringbuffer_dev_addr = DSP_RING_BUFFER_IOVA; + + if (request_mem_region(priv->dsp_iram_phyaddr, priv->dsp_iram_size, + "DSP_IRAM_BASE") == NULL) { + dev_err(sdev->dev, "request dsp iram mem region error\n"); + ret = -EBUSY; + goto err_map_rb; + } + sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, priv->dsp_iram_phyaddr, + priv->dsp_iram_size); + if (IS_ERR_OR_NULL(sdev->bar[SOF_FW_BLK_TYPE_IRAM])) { + dev_err(sdev->dev, "failed to remap dsp iram\n"); + ret = -ENOMEM; + goto err_map_iram_region; + } + sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM; + + if (request_mem_region(priv->dsp_dram_phyaddr, priv->dsp_dram_size, + "DSP_DRAM_BASE") == NULL) { + dev_err(sdev->dev, "request dsp dram mem region error\n"); + ret = -EBUSY; + goto err_map_iram_region; + } + sdev->bar[SOF_FW_BLK_TYPE_DRAM] = devm_ioremap(sdev->dev, priv->dsp_dram_phyaddr, + priv->dsp_dram_size); + if (IS_ERR_OR_NULL(sdev->bar[SOF_FW_BLK_TYPE_DRAM])) { + dev_err(sdev->dev, "failed to remap dsp dram\n"); + ret = -ENOMEM; + goto err; + } + + es_dsp_set_rate(priv, DSP_SUBSYS_HILOAD_CLK); + + return 0; +err: + release_mem_region(priv->dsp_dram_phyaddr, priv->dsp_dram_size); +err_map_iram_region: + release_mem_region(priv->dsp_iram_phyaddr, priv->dsp_iram_size); +err_map_rb: + iommu_unmap_rsv_iova(sdev->dev, NULL, + priv->ringbuffer_dev_addr, priv->ringbuffer_size); +err_map_fw: + iommu_unmap_rsv_iova(sdev->dev, priv->firmware_addr, + priv->firmware_dev_addr, DSP_FIRMWARE_IOVA_SIZE); + priv->firmware_addr = NULL; +err_map_mbox_rx: + iommu_unmap_rsv_iova(sdev->dev, NULL, priv->mbox_rx_dev_addr, + DSP_MBOX_IOVA_SIZE); +err_map_mbox_tx: + iommu_unmap_rsv_iova(sdev->dev, NULL, priv->mbox_tx_dev_addr, + DSP_MBOX_IOVA_SIZE); +err_map_uart_mutex: + iommu_unmap_rsv_iova(sdev->dev, NULL, priv->uart_mutex_dev_addr, + DSP_UART_MUTEX_IOVA_SIZE); +err_map_uart: + iommu_unmap_rsv_iova(sdev->dev, NULL, priv->uart_dev_addr, + priv->uart_reg_size); + return ret; +} \ No newline at end of file diff --git a/sound/soc/sof/eswin/es-common.h b/sound/soc/sof/eswin/es-common.h new file mode 100644 index 000000000000..415ccb866d74 --- /dev/null +++ b/sound/soc/sof/eswin/es-common.h @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ESWIN audio sof driver + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: DengLei + */ + +#ifndef __ES_COMMON_H__ +#define __ES_COMMON_H__ + +#include +#include +#include +#include +#include "eswin-dsp-subsys.h" + +#define EXCEPT_MAX_HDR_SIZE 0x400 +#define ESWIN_DSP_STACK_DUMP_SIZE 32 + +#define DSP_UART_MUTEX_IOVA 0xff5c0000 +#define DSP_UART_IOVA 0xff5d0000 +#define DSP_MBOX_TX_IOVA 0xff5e0000 +#define DSP_MBOX_RX_IOVA 0xff5f0000 +#define DSP_RING_BUFFER_IOVA 0xff600000 +#define DSP_FIRMWARE_IOVA 0xff800000 + +#define DSP_UART_MUTEX_IOVA_SIZE 0x10000 +#define DSP_MBOX_IOVA_SIZE 0x10000 +#define DSP_FIRMWARE_IOVA_SIZE 0x800000 + +#define UART_MUTEX_BASE_ADDR 0x51820000 +#define UART_MUTEX_UNIT_OFFSET 4 + +#define IPC_MSG_RQ_FLAG 1 +#define IPC_MSG_RP_FLAG 2 + +struct es_dsp_chan { + struct es_dsp_ipc *ipc; + struct mbox_client cl; + struct mbox_chan *ch; + char *name; +}; + +struct es_dsp_ops { + void (*handle_reply)(struct es_dsp_ipc *ipc); + void (*handle_request)(struct es_dsp_ipc *ipc); +}; + +struct es_dsp_ipc { + /* Host <-> DSP communication uses 2 txdb and 2 rxdb channels */ + struct es_dsp_chan chan; + struct device *dev; + struct es_dsp_ops *ops; + void *private_data; +}; + +struct es_sof_priv { + struct device *dev; + struct snd_sof_dev *sdev; + + /* DSP IPC handler */ + struct es_dsp_ipc *dsp_ipc; + struct es_dsp_subsys *dsp_subsys; + struct clk *aclk; + + u32 process_id; + u32 dsp_iram_phyaddr; + u64 dsp_iram_size; + u32 dsp_dram_phyaddr; + u64 dsp_dram_size; + u32 uart_phyaddr; + u64 uart_reg_size; + u32 uart_mutex_phyaddr; + u32 mbox_tx_phyaddr; + u32 mbox_rx_phyaddr; + u32 ringbuffer_phyaddr; + u32 ringbuffer_size; + void *firmware_addr; + dma_addr_t firmware_dev_addr; + dma_addr_t ringbuffer_dev_addr; + dma_addr_t uart_dev_addr; + dma_addr_t uart_mutex_dev_addr; + dma_addr_t mbox_tx_dev_addr; + dma_addr_t mbox_rx_dev_addr; + bool dsp_hw_init_done; +}; + +static inline void es_dsp_set_data(struct es_dsp_ipc *ipc, void *data) +{ + if (!ipc) + return; + + ipc->private_data = data; +} + +static inline void *es_dsp_get_data(struct es_dsp_ipc *ipc) +{ + if (!ipc) + return NULL; + + return ipc->private_data; +} + +void es_dsp_put_subsys(struct snd_sof_dev *sdev); + +int es_dsp_get_subsys(struct snd_sof_dev *sdev); + +int es_dsp_ring_doorbell(struct es_dsp_ipc *dsp, void *msg); + +struct mbox_chan *es_dsp_request_channel(struct es_dsp_ipc *ipc); +void es_dsp_free_channel(struct es_dsp_ipc *ipc); + +void es_dsp_dump(struct snd_sof_dev *sdev, u32 flags); + +struct es_dsp_ipc *es_ipc_init(struct snd_sof_dev *sdev); + +int es_get_hw_res(struct snd_sof_dev *sdev); + +int es_dsp_hw_init(struct snd_sof_dev *sdev); + +extern const struct dsp_arch_ops es_sof_xtensa_arch_ops; + +#endif diff --git a/sound/soc/sof/eswin/es-sof-dsp.c b/sound/soc/sof/eswin/es-sof-dsp.c new file mode 100644 index 000000000000..41cb55ba8d71 --- /dev/null +++ b/sound/soc/sof/eswin/es-sof-dsp.c @@ -0,0 +1,614 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * ESWIN audio sof driver + * + * Copyright 2024, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2. + * + * 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 for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: DengLei + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../ops.h" +#include "../sof-of-dev.h" +#include "es-common.h" + +#define MBOX_OFFSET 0x600000 +#define MBOX_SIZE 0x1000 + +#define REG_OFFSET_DSP_START 0x00 +#define REG_OFFSET_DSP_STAT 0x04 +#define REG_OFFSET_DSP_PRID 0x08 +#define REG_OFFSET_DSP_RESET 0x18 +#define REG_OFFSET_DSP_DYARID 0x504 +#define REG_OFFSET_DSP_DYAWID 0x508 +#define REG_OFFSET_USR_CONF0 0x1c + +//bit definitions for REG_OFFSET_DSP_STAT +#define DSP_STAT_REG_BIT_STAT_VECTOR_SEL BIT_ULL(0) +#define DSP_STAT_REG_BIT_ARID_DYNM_EN BIT_ULL(4) +#define DSP_STAT_REG_BITS_ARMMUSID GENMASK_ULL(23, 16) + +//bit definitions for REG_OFFSET_DSP_PRID +#define DSP_PRID_REG_BIT_PRID_MASK GENMASK_ULL(15, 0) + +//bit definitions for REG_OFFSET_DSP_RESET +#define DSP_RESET_REG_BIT_RUNSTALL_ON_RESET BIT_ULL(0) +#define DSP_RESET_REG_BIT_CORE_RESET BIT_ULL(1) +#define DSP_RESET_REG_BIT_DEBUG_RESET BIT_ULL(2) + +#define FIRMWARE_SIZE_MAX 0x800000 // 8M + +//bit definitions for REG_OFFSET_DSP_DYAWID +#define DSP_DYAWID_REG_BITS_ARMMUSID_MASK GENMASK(23, 16) +#define DSP_DYAWID_REG_BITS_AWMMUSID_MASK GENMASK(23, 16) +#define REG_DEFAULT_SIZE 0x10000 +#define REG_OFFSET_SIZE 0x20 +#define REG_OFFSET_SIZE_8 0x8 + +#define REG_OFFSET(reg, pro_id) (reg + (REG_OFFSET_SIZE * pro_id)) +#define REG_OFFSET_8(reg, pro_id) (reg + (REG_OFFSET_SIZE_8 * pro_id)) + +static int es_sof_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return MBOX_OFFSET; +} + +static int es_sof_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return MBOX_OFFSET; +} + +static void es_sof_handle_reply(struct es_dsp_ipc *ipc) +{ + struct es_sof_priv *priv = es_dsp_get_data(ipc); + unsigned long flags; + + spin_lock_irqsave(&priv->sdev->ipc_lock, flags); + snd_sof_ipc_process_reply(priv->sdev, 0); + spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); +} + +static void es_sof_handle_request(struct es_dsp_ipc *ipc) +{ + struct es_sof_priv *priv = es_dsp_get_data(ipc); + u32 p; /* Panic code */ + unsigned long flags; + spin_lock_irqsave(&priv->sdev->ipc_lock, flags); + + /* Read the message from the debug box. */ + sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p)); + + /* Check to see if the message is a panic code (0x0dead***) */ + if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC){ + snd_sof_dsp_panic(priv->sdev, p, true); + } + else + snd_sof_ipc_msgs_rx(priv->sdev); + + spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); +} + +static struct es_dsp_ops dsp_ops = { + .handle_reply = es_sof_handle_reply, + .handle_request = es_sof_handle_request, +}; + +static int es_sof_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct es_sof_priv *priv = sdev->pdata->hw_pdata; + u64 *msg_flag = kzalloc(sizeof(u64), GFP_ATOMIC); + if (!msg_flag) + return -ENOMEM; + + *msg_flag = IPC_MSG_RQ_FLAG; + + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + es_dsp_ring_doorbell(priv->dsp_ipc, msg_flag); + return 0; +} + +/* + * DSP control. + */ + +static int es_dsp_run(struct snd_sof_dev *sdev) +{ + int ret; + struct es_sof_priv *priv = (struct es_sof_priv *)sdev->pdata->hw_pdata; + + dev_info(sdev->dev, "%s\n", __func__); + + dma_sync_single_for_device(sdev->dev, priv->firmware_dev_addr, DSP_FIRMWARE_IOVA_SIZE, + DMA_BIDIRECTIONAL); + + /*dereset dsp core*/ + ret = regmap_clear_bits(priv->dsp_subsys->map, + REG_OFFSET(REG_OFFSET_DSP_RESET, priv->process_id), + DSP_RESET_REG_BIT_RUNSTALL_ON_RESET); + WARN_ON(0 != ret); + + return ret; +} + +static int es_dsp_reset(struct snd_sof_dev *sdev) +{ + int ret; + struct es_sof_priv *priv = (struct es_sof_priv *)sdev->pdata->hw_pdata; + + dev_info(sdev->dev, "%s\n", __func__); + + //halt + ret = regmap_set_bits(priv->dsp_subsys->map, + REG_OFFSET(REG_OFFSET_DSP_RESET, priv->process_id), + DSP_RESET_REG_BIT_RUNSTALL_ON_RESET); + WARN_ON(0 != ret); + /*reset dsp core*/ + ret = regmap_set_bits(priv->dsp_subsys->map, + REG_OFFSET(REG_OFFSET_DSP_RESET, + priv->process_id), + DSP_RESET_REG_BIT_DEBUG_RESET); + WARN_ON(0 != ret); + ret = regmap_set_bits(priv->dsp_subsys->map, + REG_OFFSET(REG_OFFSET_DSP_RESET, priv->process_id), + DSP_RESET_REG_BIT_CORE_RESET); + WARN_ON(0 != ret); + mdelay(20); + /*set processer id*/ + ret = regmap_write_bits(priv->dsp_subsys->map, + REG_OFFSET(REG_OFFSET_DSP_PRID, priv->process_id), + DSP_PRID_REG_BIT_PRID_MASK, priv->process_id); + WARN_ON(0 != ret); + /*set reset vector*/ + ret = regmap_write(priv->dsp_subsys->map, REG_OFFSET(REG_OFFSET_DSP_START, priv->process_id), + priv->firmware_dev_addr); + WARN_ON(0 != ret); + ret = regmap_set_bits(priv->dsp_subsys->map, REG_OFFSET(REG_OFFSET_DSP_STAT, priv->process_id), + DSP_STAT_REG_BIT_STAT_VECTOR_SEL); + WARN_ON(0 != ret); + /*dereset dsp core*/ + ret = regmap_clear_bits(priv->dsp_subsys->map, REG_OFFSET(REG_OFFSET_DSP_RESET, priv->process_id), + DSP_RESET_REG_BIT_CORE_RESET); + + /*set smmu id*/ + ret = regmap_write_bits(priv->dsp_subsys->map, REG_OFFSET_8(REG_OFFSET_DSP_DYAWID, priv->process_id), + DSP_DYAWID_REG_BITS_AWMMUSID_MASK, (WIN2030_SID_DSP_0 + priv->process_id) << 16); + WARN_ON(0 != ret); + + ret = regmap_write_bits(priv->dsp_subsys->map, REG_OFFSET_8(REG_OFFSET_DSP_DYARID, priv->process_id), + DSP_DYAWID_REG_BITS_ARMMUSID_MASK, (WIN2030_SID_DSP_0 + priv->process_id) << 16); + WARN_ON(0 != ret); + + ret = win2030_dynm_sid_enable(dev_to_node(sdev->dev)); + WARN_ON(0 != ret); + + /*enable jtag*/ + ret = regmap_write(priv->dsp_subsys->con_map, 0x330, 0xF0F0); + WARN_ON(0 != ret); + + /*dereset dsp debug*/ + ret = regmap_clear_bits(priv->dsp_subsys->map, REG_OFFSET(REG_OFFSET_DSP_RESET, priv->process_id), + DSP_RESET_REG_BIT_DEBUG_RESET); + WARN_ON(0 != ret); + + return 0; +} + +static int es_dsp_clk_enable(struct es_sof_priv *priv) +{ + int ret; + u32 val; + bool enabled; + + ret = clk_prepare_enable(priv->dsp_subsys->cfg_clk); + if (ret) { + dev_err(priv->dev, "failed to enable cfg clk, ret=%d.\n", ret); + return ret; + } + enabled = __clk_is_enabled(priv->dsp_subsys->aclk); + if (!enabled) { + ret = clk_prepare_enable(priv->dsp_subsys->aclk); + if (ret) { + dev_err(priv->dev, "failed to enable aclk: %d\n", ret); + return ret; + } + } + + regmap_read(priv->dsp_subsys->map, REG_OFFSET_USR_CONF0, &val); + val |= (3 << (priv->process_id * 2)); + ret = regmap_write(priv->dsp_subsys->map, REG_OFFSET_USR_CONF0, val); + regmap_read(priv->dsp_subsys->map, REG_OFFSET_USR_CONF0, &val); + dev_info(priv->dev, "%s, %d, val=0x%x.\n", __func__, __LINE__, val); + + return 0; +} + +static int es_dsp_probe(struct snd_sof_dev *sdev) +{ + struct es_sof_priv *priv; + int ret = 0; + + dev_info(sdev->dev, "%s\n", __func__); + + priv = devm_kzalloc(sdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + return -ENOMEM; + } + sdev->num_cores = 1; + sdev->pdata->hw_pdata = priv; + priv->dev = sdev->dev; + priv->sdev = sdev; + + ret = es_dsp_get_subsys(sdev); + if (ret) { + dev_err(sdev->dev, "get dsp subsys err, ret=%d.\n", ret); + return -ENXIO; + } + + ret = es_get_hw_res(sdev); + if (ret) { + dev_err(sdev->dev, "get hw res error.\n"); + goto err_release_subsys; + } + + /* setting for DMA check */ + ret = dma_set_mask(sdev->dev, DMA_BIT_MASK(32)); + if (ret) { + WARN_ON_ONCE(sdev->dev->dma_mask); + goto err_release_subsys; + } + + priv->dsp_ipc = es_ipc_init(sdev); + if (!priv->dsp_ipc) { + /* DSP IPC driver not probed yet, try later */ + dev_err(sdev->dev, "Failed to init ipc channel\n"); + goto err_release_subsys; + } + es_dsp_set_data(priv->dsp_ipc, priv); + priv->dsp_ipc->ops = &dsp_ops; + + ret = es_dsp_clk_enable(priv); + if (0 != ret) { + dev_err(sdev->dev, "Failed to enable subsys clk\n"); + goto err_release_ipc; + } + + ret = win2030_tbu_power(sdev->dev, true); + if (ret) { + dev_err(sdev->dev, "tbu power failed\n"); + goto err; + } + + sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; + /* set default mailbox offset for FW ready message */ + sdev->dsp_box.offset = MBOX_OFFSET; + + ret = es_dsp_hw_init(sdev); + if (ret) { + goto err; + } + priv->dsp_hw_init_done = true; + + return 0; + +err: + clk_disable_unprepare(priv->aclk); +err_release_ipc: + es_dsp_free_channel(priv->dsp_ipc); +err_release_subsys: + es_dsp_put_subsys(sdev); + return ret; +} + +static int es_dsp_remove(struct snd_sof_dev *sdev) +{ + dev_info(sdev->dev, "%s\n", __func__); + struct es_sof_priv *priv = (struct es_sof_priv *)sdev->pdata->hw_pdata; + + if (!priv || !priv->dsp_hw_init_done) { + return 0; + } + + iommu_unmap_rsv_iova(sdev->dev, NULL, priv->ringbuffer_dev_addr, + priv->ringbuffer_size); + iommu_unmap_rsv_iova(sdev->dev, priv->firmware_addr, + priv->firmware_dev_addr, DSP_FIRMWARE_IOVA_SIZE); + priv->firmware_addr = NULL; + iommu_unmap_rsv_iova(sdev->dev, NULL, priv->mbox_rx_dev_addr, + DSP_MBOX_IOVA_SIZE); + iommu_unmap_rsv_iova(sdev->dev, NULL, priv->mbox_tx_dev_addr, + DSP_MBOX_IOVA_SIZE); + iommu_unmap_rsv_iova(sdev->dev, NULL, priv->uart_mutex_dev_addr, + DSP_UART_MUTEX_IOVA_SIZE); + iommu_unmap_rsv_iova(sdev->dev, NULL, priv->uart_dev_addr, + priv->uart_reg_size); + release_mem_region(priv->dsp_iram_phyaddr, priv->dsp_iram_size); + release_mem_region(priv->dsp_dram_phyaddr, priv->dsp_dram_size); + + es_dsp_free_channel(priv->dsp_ipc); + es_dsp_put_subsys(sdev); + return 0; +} + +static int es_sof_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + /* Only IRAM and SRAM bars are valid */ + switch (type) { + case SOF_FW_BLK_TYPE_IRAM: + case SOF_FW_BLK_TYPE_DRAM: + case SOF_FW_BLK_TYPE_SRAM: + return type; + default: + dev_err(sdev->dev, "error type:%d\n", type); + return -EINVAL; + } +} + +static struct snd_soc_dai_driver es_sof_dai[] = { +{ + .name = "dsp_port", + .playback = { + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + }, +}, +{ + .name = "dsp_port2", + .playback = { + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + }, +}, +{ + .name = "dsp_port3", + .playback = { + .channels_min = 2, + .channels_max = 2, + }, + .capture = { + .channels_min = 2, + .channels_max = 2, + }, +}, +}; + +static int es_sof_dsp_set_power_state(struct snd_sof_dev *sdev, + const struct sof_dsp_power_state *target_state) +{ + sdev->dsp_power_state = *target_state; + + return 0; +} + +static int es_sof_resume(struct snd_sof_dev *sdev) +{ + struct es_sof_priv *priv = (struct es_sof_priv *)sdev->pdata->hw_pdata; + + es_dsp_request_channel(priv->dsp_ipc); + return 0; +} + +static void es_sof_suspend(struct snd_sof_dev *sdev) +{ + struct es_sof_priv *priv = (struct es_sof_priv *)sdev->pdata->hw_pdata; + + es_dsp_free_channel(priv->dsp_ipc); +} + +static int es_sof_dsp_runtime_resume(struct snd_sof_dev *sdev) +{ + int ret; + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D0, + }; + + ret = es_sof_resume(sdev); + if (ret < 0) + return ret; + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int es_sof_dsp_runtime_suspend(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D3, + }; + + es_sof_suspend(sdev); + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int es_sof_dsp_resume(struct snd_sof_dev *sdev) +{ + int ret; + const struct sof_dsp_power_state target_dsp_state = { + .state = SOF_DSP_PM_D0, + }; + + ret = es_sof_resume(sdev); + if (ret < 0) + return ret; + + if (pm_runtime_suspended(sdev->dev)) { + pm_runtime_disable(sdev->dev); + pm_runtime_set_active(sdev->dev); + pm_runtime_mark_last_busy(sdev->dev); + pm_runtime_enable(sdev->dev); + pm_runtime_idle(sdev->dev); + } + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static int es_sof_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state) +{ + const struct sof_dsp_power_state target_dsp_state = { + .state = target_state, + }; + + if (!pm_runtime_suspended(sdev->dev)) + es_sof_suspend(sdev); + + return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); +} + +static struct snd_soc_acpi_mach *es_sof_machine_select(struct snd_sof_dev *sdev) +{ + struct snd_sof_pdata *sof_pdata = sdev->pdata; + struct snd_soc_acpi_mach *mach; + + mach = devm_kmalloc(sdev->dev, sizeof(struct snd_soc_acpi_mach), GFP_KERNEL); + if (!mach) { + dev_warn(sdev->dev, "warning: alloc machine info failed\n"); + return NULL; + } + + sof_pdata->tplg_filename = "sof-esw-es8388.tplg"; + mach->sof_tplg_filename = "sof-esw-es8388.tplg"; + mach->drv_name = "asoc-simple-card"; + + return mach; +} + + +static struct snd_sof_dsp_ops sof_es_sof_ops = { + /* probe and remove */ + .probe = es_dsp_probe, + .remove = es_dsp_remove, + /* DSP core boot */ + .run = es_dsp_run, + .reset = es_dsp_reset, + + /* Block IO */ + .block_read = sof_block_read, + .block_write = sof_block_write, + + /* Mailbox IO */ + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, + + /* ipc */ + .send_msg = es_sof_send_msg, + + .get_mailbox_offset = es_sof_get_mailbox_offset, + .get_window_offset = es_sof_get_window_offset, + + .ipc_msg_data = sof_ipc_msg_data, + .set_stream_data_offset = sof_set_stream_data_offset, + + .get_bar_index = es_sof_get_bar_index, + /* firmware loading */ + .load_firmware = snd_sof_load_firmware_memcpy, + + /* Debug information */ + .dbg_dump = es_dsp_dump, + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, + + /* stream callbacks */ + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + /* Firmware ops */ + .dsp_arch_ops = &es_sof_xtensa_arch_ops, + + /* machine driver */ + .machine_select = es_sof_machine_select, + + /* DAI drivers */ + .drv = es_sof_dai, + .num_drv = ARRAY_SIZE(es_sof_dai), + + .suspend = es_sof_dsp_suspend, + .resume = es_sof_dsp_resume, + + .runtime_suspend = es_sof_dsp_runtime_suspend, + .runtime_resume = es_sof_dsp_runtime_resume, + + .set_power_state = es_sof_dsp_set_power_state, + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; + +static struct sof_dev_desc sof_of_es_sof_desc = { + .ipc_supported_mask = BIT(SOF_IPC), + .ipc_default = SOF_IPC, + .ipc_timeout = 3000, + .boot_timeout = 5000, + .default_fw_path = { + [SOF_IPC] = "eswin", + }, + .default_tplg_path = { + [SOF_IPC] = "eswin", + }, + .default_fw_filename = { + [SOF_IPC] = "sof-2030.ri", + }, + .nocodec_tplg_filename = "sof-esw-es8388.tplg", + .ops = &sof_es_sof_ops, +}; + +static const struct of_device_id sof_of_es_sof_ids[] = { + { .compatible = "eswin,sof-dsp", .data = &sof_of_es_sof_desc}, + { } +}; +MODULE_DEVICE_TABLE(of, sof_of_es_sof_ids); + +/* DT driver definition */ +static struct platform_driver snd_sof_of_es_sof_driver = { + .probe = sof_of_probe, + .remove = sof_of_remove, + .driver = { + .name = "sof-audio-of-es-dsp", + .of_match_table = sof_of_es_sof_ids, + }, +}; +module_platform_driver(snd_sof_of_es_sof_driver); + +MODULE_AUTHOR("DengLei "); +MODULE_DESCRIPTION("ESWIN I2S SoC Interface"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:eswin dsp driver"); -- 2.47.0