From 3e3aa7602d855e2ab0151ebd4b63c13fa2e78bfa Mon Sep 17 00:00:00 2001 From: linmin Date: Thu, 11 Apr 2024 18:09:23 +0800 Subject: [PATCH 004/219] feat(eswin memory):Added eswin memory related changes Changelogs: 1.Exported arch_sync_dma_for_xx() API for eswin heap and vb 2.Added buddy.h 3.Added llc_spram driver code 4.Added eswin memblock driver code 5.Added eswin_npu.h 7.Added "dma-noncoherent;" property in the EIC770 dtsi for all the devices, because the default property on linux-6.6 for riscv archtecture is dma-coherent, this is not true for ESWIN_EIC770X_SOC_FAMILY. --- arch/riscv/boot/dts/eswin/eic7700-evb.dts | 4 - .../dts/eswin/eswin-win2030-die0-soc.dtsi | 65 +- .../dts/eswin/eswin-win2030-die1-soc.dtsi | 43 + arch/riscv/boot/dts/eswin/eswin-win2030.dts | 4 - arch/riscv/configs/win2030_defconfig | 1 + arch/riscv/mm/dma-noncoherent.c | 6 + drivers/memory/Kconfig | 1 + drivers/memory/Makefile | 1 + drivers/memory/eswin/Kconfig | 29 + drivers/memory/eswin/Makefile | 4 + drivers/memory/eswin/buddy.h | 226 +++ drivers/memory/eswin/codacache/Kconfig | 16 + drivers/memory/eswin/codacache/Makefile | 2 + drivers/memory/eswin/codacache/llc_spram.c | 1576 +++++++++++++++++ drivers/memory/eswin/codacache/llc_spram.h | 90 + .../memory/eswin/eswin_cpuid_hartid_convert.c | 39 + .../memory/eswin/eswin_cpuid_hartid_convert.h | 32 + drivers/memory/eswin/eswin_memblock.c | 170 ++ drivers/memory/eswin/eswin_memblock.h | 18 + include/linux/eswin-win2030-sid-cfg.h | 12 + include/linux/eswin_npu.h | 21 + 21 files changed, 2336 insertions(+), 24 deletions(-) create mode 100644 drivers/memory/eswin/Kconfig create mode 100644 drivers/memory/eswin/Makefile create mode 100644 drivers/memory/eswin/buddy.h create mode 100644 drivers/memory/eswin/codacache/Kconfig create mode 100644 drivers/memory/eswin/codacache/Makefile create mode 100644 drivers/memory/eswin/codacache/llc_spram.c create mode 100644 drivers/memory/eswin/codacache/llc_spram.h create mode 100644 drivers/memory/eswin/eswin_cpuid_hartid_convert.c create mode 100644 drivers/memory/eswin/eswin_cpuid_hartid_convert.h create mode 100644 drivers/memory/eswin/eswin_memblock.c create mode 100644 drivers/memory/eswin/eswin_memblock.h create mode 100644 include/linux/eswin-win2030-sid-cfg.h create mode 100644 include/linux/eswin_npu.h diff --git a/arch/riscv/boot/dts/eswin/eic7700-evb.dts b/arch/riscv/boot/dts/eswin/eic7700-evb.dts index 07976356e5b5..358ea4e7ac84 100644 --- a/arch/riscv/boot/dts/eswin/eic7700-evb.dts +++ b/arch/riscv/boot/dts/eswin/eic7700-evb.dts @@ -180,10 +180,6 @@ &smmu_pmu0 { status = "disabled"; }; -&dev_foo_b { - status = "disabled"; -}; - &dev_foo_a { status = "okay"; }; 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 0a81e221150c..c3bbfab6fb47 100644 --- a/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi +++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die0-soc.dtsi @@ -257,6 +257,7 @@ smmu0: iommu@50c00000 { "tbu4_rst", "tbu5_rst", "tbu6_rst", "tbu7_rst"; status = "disabled"; numa-node-id = <0>; + dma-noncoherent; }; smmu_pmu0: pmu@50c02000 { @@ -268,24 +269,14 @@ smmu_pmu0: pmu@50c02000 { interrupts = <363>; status = "disabled"; numa-node-id = <0>; - }; - - dev_foo_b: E21@1 { - compatible = "riscv,dev-foo-b"; - #size-cells = <2>; - - dma-ranges = <0x0 0x20000000 0x0 0xc0000000 0x0 0x40000000>; - iommus = <&smmu0 WIN2030_SID_DEV_FOO_B>; - tbus = ; - numa-node-id = <0>; - status = "disabled"; + dma-noncoherent; }; dev_foo_a: E21@0 { compatible = "riscv,dev-foo-a"; #size-cells = <2>; dma-ranges = <0x0 0x20000000 0x0 0xc0000000 0x0 0x40000000>; - iommus = <&smmu0 WIN2030_SID_DEV_FOO_A>; + /*iommus = <&smmu0 WIN2030_SID_DEV_FOO_A>;*/ tbus = ; /* tbus = , @@ -295,6 +286,7 @@ dev_foo_a: E21@0 { */ status = "disabled"; numa-node-id = <0>; + dma-noncoherent; }; d0_pmu: power-controller@51808000 { @@ -399,6 +391,7 @@ d0_dmac0: dma-controller-hsp@0x50430000 { eswin,hsp_sp_csr = <&d0_hsp_sp_csr 0x104c>; eswin,syscfg = <&d0_sys_con DMA1_SID_REG_OFFSET 0x370>; numa-node-id = <0>; + dma-noncoherent; }; d0_aon_dmac: dma-controller-aon@0x518c0000 { @@ -426,6 +419,7 @@ d0_aon_dmac: dma-controller-aon@0x518c0000 { tbus = ; eswin,syscfg = <&d0_sys_con DMA1_SID_REG_OFFSET 0x370>; numa-node-id = <0>; + dma-noncoherent; }; d0_gmac0: ethernet@50400000 { @@ -446,6 +440,7 @@ d0_gmac0: ethernet@50400000 { reset-names = "ethrst"; 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>; snps,axi-config = <&d0_stmmac_axi_setup>; @@ -475,6 +470,7 @@ d0_gmac1: ethernet@50410000 { reset-names = "ethrst"; 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>; snps,axi-config = <&d0_stmmac_axi_setup_gmac1>; @@ -511,6 +507,7 @@ d0_nvdla: nvdla-controller@51c00000 { reset-names = "e31_core"; numa-node-id = <0>; + dma-noncoherent; }; dev_llc_d0: llc@51c00000 { @@ -575,6 +572,7 @@ ESWIN_MAILBOX_U84_TO_DSP_0_REG_BASE dma-ranges = <0x30000000 0x0 0xc0000000 0xce000000>; iommus = <&smmu0 WIN2030_SID_DSP_0>; tbus = ; + dma-noncoherent; numa-node-id = <0>; aux-e31-dtim = <0x5a110000>; dsp@0 { @@ -603,6 +601,7 @@ ESWIN_MAILBOX_U84_TO_DSP_1_REG_BASE dma-ranges = <0x30000000 0x0 0xc0000000 0xce000000>; iommus = <&smmu0 WIN2030_SID_DSP_1>; tbus = ; + dma-noncoherent; numa-node-id = <0>; aux-e31-dtim = <0x5a110000>; dsp@0 { @@ -631,6 +630,7 @@ ESWIN_MAILBOX_U84_TO_DSP_2_REG_BASE dma-ranges = <0x30000000 0x0 0xc0000000 0xce000000>; iommus = <&smmu0 WIN2030_SID_DSP_2>; tbus = ; + dma-noncoherent; numa-node-id = <0>; aux-e31-dtim = <0x5a110000>; dsp@0 { @@ -659,6 +659,7 @@ ESWIN_MAILBOX_U84_TO_DSP_3_REG_BASE dma-ranges = <0x30000000 0x0 0xc0000000 0xce000000>; iommus = <&smmu0 WIN2030_SID_DSP_3>; tbus = ; + dma-noncoherent; numa-node-id = <0>; aux-e31-dtim = <0x5a110000>; dsp@0 { @@ -685,6 +686,7 @@ d0_sofdsp: sofdsp@4 { mailbox-u84-to-dsp-addr = ; dsp-uart = <&d0_uart1>; ringbuffer-region = <&dsp_reserved1>; + dma-noncoherent; }; }; @@ -714,6 +716,7 @@ gc820: g2d@50140000 { enable-mmu = <1>; contiguous-size = <0xa00000>; recovery = <0>; + dma-noncoherent; }; gpu0: gpu@51400000 { @@ -733,6 +736,7 @@ gpu0: gpu@51400000 { reset-names = "axi", "cfg", "gray", "jones","spu"; interrupt-parent = <&plic0>; interrupts = <15>; + dma-noncoherent; }; d0_sata: sata@0x50420000{ @@ -754,6 +758,7 @@ d0_sata: sata@0x50420000{ eswin,hsp_sp_csr = <&d0_hsp_sp_csr 0x1050>; eswin,syscrg_csr = <&d0_sys_crg 0x41c>; numa-node-id = <0>; + dma-noncoherent; }; pcie: pcie@0x54000000 { @@ -803,6 +808,7 @@ msi_ctrl_int : 220 tbus = ; status = "disabled"; numa-node-id = <0>; + dma-noncoherent; }; ssi0: spi0@50810000 { @@ -822,6 +828,7 @@ ssi0: spi0@50810000 { dma-names = "rx", "tx"; numa-node-id = <0>; status = "disabled"; + dma-noncoherent; }; ssi1: spi1@50814000 { @@ -841,6 +848,7 @@ ssi1: spi1@50814000 { dma-names = "rx", "tx"; numa-node-id = <0>; status = "disabled"; + dma-noncoherent; }; sdhci_emmc: mmc@50450000 { @@ -880,6 +888,7 @@ sdhci_emmc: mmc@50450000 { eswin,hsp_sp_csr = <&d0_hsp_sp_csr 0x1038>; status = "disabled"; numa-node-id = <0>; + dma-noncoherent; }; sdio0: mmc@0x50460000{ @@ -916,6 +925,7 @@ sdio0: mmc@0x50460000{ sdio-id = <0>; numa-node-id = <0>; status = "disabled"; + dma-noncoherent; }; sdio1: mmc@0x50470000{ @@ -952,6 +962,7 @@ sdio1: mmc@0x50470000{ sdio-id = <1>; numa-node-id = <0>; status = "disabled"; + dma-noncoherent; }; vdec0: video-decoder0@50100000 { @@ -987,6 +998,7 @@ vdec0: video-decoder0@50100000 { vccsr-reg = <0x0 0x501c0000 0x0 0x1000>; numa-node-id = <0>; tbus = , ; + dma-noncoherent; vdec_0: vdec0@50100000 { core-name = "video-dec0"; @@ -1034,6 +1046,7 @@ venc0: video-encoder@50110000 { vccsr-reg = <0x0 0x501c0000 0x0 0x1000>; numa-node-id = <0>; tbus = , ; + dma-noncoherent; venc_0: venc0@50110000 { core-name = "video-enc0"; @@ -1064,6 +1077,7 @@ d0_mbox0: mbox@50a00000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & lpcpu*/ @@ -1082,6 +1096,7 @@ d0_mbox1: mbox@50a20000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & npu_0*/ @@ -1100,6 +1115,7 @@ d0_mbox2: mbox@50a40000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & npu_1*/ @@ -1118,6 +1134,7 @@ d0_mbox3: mbox@50a60000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & dsp_0*/ @@ -1136,6 +1153,7 @@ d0_mbox4: mbox@50a80000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & dsp_1*/ @@ -1154,6 +1172,7 @@ d0_mbox5: mbox@50aa0000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & dsp_2*/ @@ -1172,6 +1191,7 @@ d0_mbox6: mbox@50ac0000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & dsp_3*/ @@ -1190,6 +1210,7 @@ d0_mbox7: mbox@50ae0000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; d0_ipc_scpu:ipc@0 { @@ -1203,6 +1224,7 @@ d0_ipc_scpu:ipc@0 { mboxes = <&d0_mbox0 0>; mbox-names = "u84_scpu"; numa-node-id = <0>; + dma-noncoherent; }; d0_lpcpu:lpcpu@0 { @@ -1226,6 +1248,7 @@ d0_lpcpu:lpcpu@0 { mbox-names = "u84_lpcpu"; numa-node-id = <0>; status = "disabled"; + dma-noncoherent; }; pvt0: pvt@0x50b00000 { @@ -1757,6 +1780,7 @@ d0_i2s0: i2s0@50200000 { <&d0_reset VO_I2SRST_CTRL SW_VO_I2S_PRSTN>, <&d0_reset VO_PHYRST_CTRL SW_VO_PRSTN>; reset-names = "i2srst", "i2sprst", "voprst"; + dma-noncoherent; }; d0_i2s1: i2s1@50210000 { @@ -1774,6 +1798,7 @@ d0_i2s1: i2s1@50210000 { <&d0_reset VO_I2SRST_CTRL SW_VO_I2S_PRSTN>, <&d0_reset VO_PHYRST_CTRL SW_VO_PRSTN>; reset-names = "i2srst", "i2sprst", "voprst"; + dma-noncoherent; }; d0_i2s2: i2s2@50220000 { @@ -1791,6 +1816,7 @@ d0_i2s2: i2s2@50220000 { <&d0_reset VO_I2SRST_CTRL SW_VO_I2S_PRSTN>, <&d0_reset VO_PHYRST_CTRL SW_VO_PRSTN>; reset-names = "i2srst", "i2sprst", "voprst"; + dma-noncoherent; }; d0_soundcard: soundcard { @@ -1871,6 +1897,7 @@ dc8k: dc8000@502c0000 { <&d0_reset VO_RST_CTRL SW_VO_DC_RSTN>, <&d0_reset VO_RST_CTRL SW_VO_DC_PRSTN>; reset-names = "vo_arst", "vo_prst", "dc_arst", "dc_prst"; + dma-noncoherent; dc_out: port { #address-cells = <1>; @@ -1886,10 +1913,10 @@ dc_out_dpi1: endpoint@1 { remote-endpoint = <&vd_input>; }; - dc_out_hdmi: endpoint@2 { - reg = <2>; - remote-endpoint = <&hdmi_in_dc8k>; - }; + dc_out_hdmi: endpoint@2 { + reg = <2>; + remote-endpoint = <&hdmi_in_dc8k>; + }; }; }; @@ -2086,6 +2113,7 @@ d0_usbdrd_dwc3_0: dwc3@50480000 { status = "disabled"; numa-node-id = <0>; tbus = ; + dma-noncoherent; }; }; @@ -2125,6 +2153,7 @@ d0_usbdrd_dwc3_1: dwc3@50490000 { status = "disabled"; numa-node-id = <0>; tbus = ; + dma-noncoherent; }; }; @@ -2181,6 +2210,7 @@ isp_0: isp@0x51000000 { tbus = ; eswin,vi_top_csr = <&vi_top_csr 0x1000>; numa-node-id = <0>; + dma-noncoherent; }; isp_1: isp@0x51010000 { @@ -2196,6 +2226,7 @@ isp_1: isp@0x51010000 { tbus = ; eswin,vi_top_csr = <&vi_top_csr 0x1004>; numa-node-id = <0>; + dma-noncoherent; }; dw200: dw200@51020000 { @@ -2222,6 +2253,7 @@ dw200: dw200@51020000 { eswin,vi_top_csr = <&vi_top_csr 0x1008>; reg = <0x0 0x51020000 0x0 0xc00>, <0x0 0x51020c00 0x0 0x120>; numa-node-id = <0>; + dma-noncoherent; }; mipi_dphy_rx: dphy@510c0000 { @@ -2379,6 +2411,7 @@ d0_numa_sample:numa_sample@0 { tbus = ; numa-node-id = <0>; status = "disabled"; + dma-noncoherent; }; ddr0: ddr-controller@0 { 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 6c887ecdc68a..acd83f4bb20d 100644 --- a/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi +++ b/arch/riscv/boot/dts/eswin/eswin-win2030-die1-soc.dtsi @@ -211,6 +211,7 @@ smmu1: iommu@70c00000 { "tbu4_rst", "tbu5_rst", "tbu6_rst", "tbu7_rst"; status = "disabled"; numa-node-id = <1>; + dma-noncoherent; }; smmu_pmu1: pmu@70c02000 { @@ -222,6 +223,7 @@ smmu_pmu1: pmu@70c02000 { interrupts = <363>; status = "disabled"; numa-node-id = <1>; + dma-noncoherent; }; dev_foo_for_die1_mapping: E21@2 { @@ -231,6 +233,7 @@ dev_foo_for_die1_mapping: E21@2 { iommus = <&smmu1 WIN2030_SID_DEV_FOO_FOR_DIE1>; status = "disabled"; numa-node-id = <1>; + dma-noncoherent; }; d1_pmu: power-controller@71808000 { @@ -335,6 +338,7 @@ d1_dmac0: dma-controller-hsp@0x70430000 { eswin,hsp_sp_csr = <&d1_hsp_sp_csr 0x104c>; eswin,syscfg = <&d1_sys_con DMA1_SID_REG_OFFSET 0x370>; numa-node-id = <1>; + dma-noncoherent; }; d1_aon_dmac: dma-controller-aon@0x718c0000 { @@ -362,6 +366,7 @@ d1_aon_dmac: dma-controller-aon@0x718c0000 { tbus = ; eswin,syscfg = <&d1_sys_con DMA1_SID_REG_OFFSET 0x370>; numa-node-id = <1>; + dma-noncoherent; }; noc { compatible = "eswin,noc","simple-bus"; @@ -403,6 +408,7 @@ vdec1: video-decoder1@70100000 { vccsr-reg = <0x0 0x701c0000 0x0 0x1000>; numa-node-id = <1>; tbus = , ; + dma-noncoherent; vdec_1: vdec1@70100000 { core-name = "video-dec0"; @@ -450,6 +456,7 @@ venc1: video-encoder@70110000 { vccsr-reg = <0x0 0x701c0000 0x0 0x1000>; numa-node-id = <1>; tbus = , ; + dma-noncoherent; venc_1: venc0@70110000 { core-name = "video-enc0"; @@ -479,6 +486,7 @@ d1_mbox0: mbox@70a00000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & lpcpu*/ @@ -497,6 +505,7 @@ d1_mbox1: mbox@70a20000 { clock-names = "pclk_mailbox_host", "pclk_mailbox_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & npu_0*/ @@ -515,6 +524,7 @@ d1_mbox2: mbox@70a40000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & npu_1*/ @@ -533,6 +543,7 @@ d1_mbox3: mbox@70a60000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & dsp_0*/ @@ -551,6 +562,7 @@ d1_mbox4: mbox@70a80000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & dsp_1*/ @@ -569,6 +581,7 @@ d1_mbox5: mbox@70aa0000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & dsp_2*/ @@ -587,6 +600,7 @@ d1_mbox6: mbox@70ac0000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; /*mailbox between u84 & dsp_3*/ @@ -605,6 +619,7 @@ d1_mbox7: mbox@70ae0000 { reset-names = "rst", "rst_device"; lock-bit = ; irq-bit = ; + dma-noncoherent; }; d1_ipc_scpu:ipc@1 { @@ -617,6 +632,7 @@ d1_ipc_scpu:ipc@1 { mboxes = <&d1_mbox0 0>; mbox-names = "u84_scpu"; numa-node-id = <1>; + dma-noncoherent; }; d1_lpcpu:lpcpu@1 { @@ -640,6 +656,7 @@ d1_lpcpu:lpcpu@1 { mbox-names = "u84_lpcpu"; numa-node-id = <1>; status = "disabled"; + dma-noncoherent; }; d1_pvt0: pvt@0x70b00000 { @@ -902,6 +919,7 @@ d1_nvdla: nvdla-controller@71c00000 { reset-names = "e31_core"; numa-node-id = <1>; + dma-noncoherent; }; dev_llc_d1: llc@71c00000 { @@ -943,6 +961,7 @@ d1_gpu: gpu@71400000 { reset-names = "axi", "cfg", "gray", "jones","spu"; interrupt-parent = <&plic1>; interrupts = <15>; + dma-noncoherent; }; d1_sata: sata@0x70420000 { @@ -964,6 +983,7 @@ d1_sata: sata@0x70420000 { eswin,hsp_sp_csr = <&d1_hsp_sp_csr 0x1050>; eswin,syscrg_csr = <&d1_sys_crg 0x41c>; numa-node-id = <1>; + dma-noncoherent; }; d1_pinctrl: pinctrl@0x71600080 { @@ -1182,6 +1202,7 @@ d1_i2s0: i2s0@70200000 { resets = <&d1_reset VO_I2SRST_CTRL SW_VO_I2S_RSTN>, <&d1_reset VO_I2SRST_CTRL SW_VO_I2S_PRSTN>; reset-names = "i2srst", "i2sprst"; + dma-noncoherent; ports { d1_i2s0_port: port@0 { d1_i2s0_endpoint: endpoint { @@ -1206,6 +1227,7 @@ d1_i2s1: i2s1@70210000 { resets = <&d1_reset VO_I2SRST_CTRL SW_VO_I2S_RSTN>, <&d1_reset VO_I2SRST_CTRL SW_VO_I2S_PRSTN>; reset-names = "i2srst", "i2sprst"; + dma-noncoherent; ports { d1_i2s1_port: port@0 { d1_i2s1_endpoint: endpoint { @@ -1230,6 +1252,7 @@ d1_i2s2: i2s@70220000 { resets = <&d1_reset VO_I2SRST_CTRL SW_VO_I2S_RSTN>, <&d1_reset VO_I2SRST_CTRL SW_VO_I2S_PRSTN>; reset-names = "i2srst", "i2sprst"; + dma-noncoherent; ports { d1_i2s2_port: port@0 { d1_i2s2_endpoint: endpoint { @@ -1280,6 +1303,7 @@ ESWIN_MAILBOX_WR_LOCK_BIT_DSP_0 dma-ranges = <0x30000000 0x0 0xc0000000 0xce000000>; iommus = <&smmu1 WIN2030_SID_DSP_0>; tbus = ; + dma-noncoherent; numa-node-id = <1>; aux-e31-dtim = <0x7a110000>; dsp@0 { @@ -1308,6 +1332,7 @@ ESWIN_MAILBOX_WR_LOCK_BIT_DSP_1 dma-ranges = <0x30000000 0x0 0xc0000000 0xce000000>; iommus = <&smmu1 WIN2030_SID_DSP_1>; tbus = ; + dma-noncoherent; numa-node-id = <1>; aux-e31-dtim = <0x7a110000>; dsp@0 { @@ -1336,6 +1361,7 @@ ESWIN_MAILBOX_WR_LOCK_BIT_DSP_2 dma-ranges = <0x30000000 0x0 0xc0000000 0xce000000>; iommus = <&smmu1 WIN2030_SID_DSP_2>; tbus = ; + dma-noncoherent; numa-node-id = <1>; aux-e31-dtim = <0x7a110000>; dsp@0 { @@ -1364,6 +1390,7 @@ ESWIN_MAILBOX_WR_LOCK_BIT_DSP_3 dma-ranges = <0x30000000 0x0 0xc0000000 0xce000000>; iommus = <&smmu1 WIN2030_SID_DSP_3>; tbus = ; + dma-noncoherent; numa-node-id = <1>; aux-e31-dtim = <0x7a110000>; dsp@0 { @@ -1391,6 +1418,7 @@ d1_sofdsp: sofdsp@4 { dsp-uart = <&d1_uart1>; ringbuffer-region = <&dsp_reserved1>; numa-node-id = <1>; + dma-noncoherent; }; }; die1_rtc: rtc@71818000 { @@ -1454,6 +1482,7 @@ msi_ctrl_int : 220 tbus = ; status = "disabled"; numa-node-id = <1>; + dma-noncoherent; }; d1_gmac0: ethernet@70400000 { @@ -1474,6 +1503,7 @@ d1_gmac0: ethernet@70400000 { reset-names = "ethrst"; 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>; snps,axi-config = <&d1_stmmac_axi_setup>; @@ -1503,6 +1533,7 @@ d1_gmac1: ethernet@70410000 { reset-names = "ethrst"; 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>; snps,axi-config = <&d1_stmmac_axi_setup_gmac1>; @@ -1547,6 +1578,7 @@ d1_sdio0: mmc@0x70460000{ sdio-id = <0>; numa-node-id = <1>; status = "disabled"; + dma-noncoherent; }; d1_sdio1: mmc@0x70470000{ @@ -1582,6 +1614,7 @@ d1_sdio1: mmc@0x70470000{ sdio-id = <1>; numa-node-id = <1>; status = "disabled"; + dma-noncoherent; }; d1_ssi0: spi1@70810000 { @@ -1601,6 +1634,7 @@ d1_ssi0: spi1@70810000 { dma-names = "rx", "tx"; numa-node-id = <1>; status = "disabled"; + dma-noncoherent; d1_spi_demo: spi-demo@0 { compatible = "eswin,demo-spi"; reg = <0 0 0 0>; @@ -1630,6 +1664,7 @@ d1_dc8k: dc8000@702c0000 { <&d1_reset VO_RST_CTRL SW_VO_DC_RSTN>, <&d1_reset VO_RST_CTRL SW_VO_DC_PRSTN>; reset-names = "vo_arst", "vo_prst", "dc_arst", "dc_prst"; + dma-noncoherent; d1_dc_out: port { @@ -1873,6 +1908,7 @@ d1_gc820: g2d@70140000 { enable-mmu = <1>; contiguous-size = <0xa00000>; recovery = <0>; + dma-noncoherent; }; d1_sdhci_emmc: mmc@70450000 { @@ -1912,6 +1948,7 @@ d1_sdhci_emmc: mmc@70450000 { eswin,hsp_sp_csr = <&d1_hsp_sp_csr 0x1038>; status = "disabled"; numa-node-id = <1>; + dma-noncoherent; }; d1_soundcard: soundcard { @@ -2031,6 +2068,7 @@ d1_usbdrd_dwc3_0: dwc3@70480000 { status = "disabled"; numa-node-id = <1>; tbus = ; + dma-noncoherent; }; }; @@ -2070,6 +2108,7 @@ d1_usbdrd_dwc3_1: dwc3@70490000 { status = "disabled"; numa-node-id = <1>; tbus = ; + dma-noncoherent; }; }; @@ -2124,6 +2163,7 @@ d1_isp_0: isp@0x71000000 { iommus = <&smmu1 WIN2030_SID_ISP0>; eswin,vi_top_csr = <&d1_vi_top_csr 0x1000>; numa-node-id = <1>; + dma-noncoherent; }; d1_isp_1: isp@0x71010000 { @@ -2137,6 +2177,7 @@ d1_isp_1: isp@0x71010000 { iommus = <&smmu1 WIN2030_SID_ISP1>; eswin,vi_top_csr = <&d1_vi_top_csr 0x1004>; numa-node-id = <1>; + dma-noncoherent; }; d1_dw200: dw200@71020000 { @@ -2162,6 +2203,7 @@ d1_dw200: dw200@71020000 { eswin,vi_top_csr = <&d1_vi_top_csr 0x1008>; reg = <0x0 0x71020000 0x0 0xc00>, <0x0 0x71020c00 0x0 0x120>; numa-node-id = <1>; + dma-noncoherent; }; d1_mipi_dphy_rx: dphy@710c0000 { @@ -2317,6 +2359,7 @@ d1_numa_sample:numa_sample@1 { dma-ranges = <0x0 0x80000000 0x0 0xc0000000 0x0 0x80000000>; iommus = <&smmu1 WIN2030_SID_SCPU>; numa-node-id = <1>; + dma-noncoherent; }; }; diff --git a/arch/riscv/boot/dts/eswin/eswin-win2030.dts b/arch/riscv/boot/dts/eswin/eswin-win2030.dts index 88696f5cba89..3b4815537560 100644 --- a/arch/riscv/boot/dts/eswin/eswin-win2030.dts +++ b/arch/riscv/boot/dts/eswin/eswin-win2030.dts @@ -488,10 +488,6 @@ &smmu_pmu0 { status = "disabled"; }; -&dev_foo_b { - status = "disabled"; -}; - &dev_foo_a { status = "okay"; }; diff --git a/arch/riscv/configs/win2030_defconfig b/arch/riscv/configs/win2030_defconfig index 030907121d03..0fc2a5f9522b 100644 --- a/arch/riscv/configs/win2030_defconfig +++ b/arch/riscv/configs/win2030_defconfig @@ -226,6 +226,7 @@ CONFIG_MAILBOX=y CONFIG_RPMSG_VIRTIO=y CONFIG_ARCH_ESWIN_EIC770X_SOC_FAMILY=y CONFIG_EXTCON=y +CONFIG_MEMORY=y CONFIG_PWM=y CONFIG_RESET_ESWIN_WIN2030=y CONFIG_INTERCONNECT=y diff --git a/arch/riscv/mm/dma-noncoherent.c b/arch/riscv/mm/dma-noncoherent.c index 807cf361156e..898a9c8facd4 100644 --- a/arch/riscv/mm/dma-noncoherent.c +++ b/arch/riscv/mm/dma-noncoherent.c @@ -95,6 +95,9 @@ void arch_sync_dma_for_device(phys_addr_t paddr, size_t size, break; } } +#if IS_ENABLED(CONFIG_ARCH_ESWIN_EIC770X_SOC_FAMILY) +EXPORT_SYMBOL(arch_sync_dma_for_device); +#endif void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, enum dma_data_direction dir) @@ -114,6 +117,9 @@ void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size, break; } } +#if IS_ENABLED(CONFIG_ARCH_ESWIN_EIC770X_SOC_FAMILY) +EXPORT_SYMBOL(arch_sync_dma_for_cpu); +#endif void arch_dma_prep_coherent(struct page *page, size_t size) { diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index c82d8d8a16ea..24faad30a79f 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -227,5 +227,6 @@ config STM32_FMC2_EBI source "drivers/memory/samsung/Kconfig" source "drivers/memory/tegra/Kconfig" +source "drivers/memory/eswin/Kconfig" endif diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index d2e6ca9abbe0..e1459a3760a3 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_STM32_FMC2_EBI) += stm32-fmc2-ebi.o obj-$(CONFIG_SAMSUNG_MC) += samsung/ obj-$(CONFIG_TEGRA_MC) += tegra/ +obj-$(CONFIG_ESWIN_MC) += eswin/ obj-$(CONFIG_TI_EMIF_SRAM) += ti-emif-sram.o obj-$(CONFIG_FPGA_DFL_EMIF) += dfl-emif.o diff --git a/drivers/memory/eswin/Kconfig b/drivers/memory/eswin/Kconfig new file mode 100644 index 000000000000..8f85e3cb466b --- /dev/null +++ b/drivers/memory/eswin/Kconfig @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: GPL-2.0 +config ESWIN_MC + bool "ESWIN Memory Controller and reserved memory block support" + default y + depends on ARCH_ESWIN_EIC770X_SOC_FAMILY + select SG_SPLIT + help + This driver supports the Memory Controller (MC) hardware, especialy for + LLC SPRAM controller, found on ESWIN SoCs. And the memblock of the reserved + memory declared with the compatible = "eswin-reserve-memory" property in dts + is also initialized. + +if ESWIN_MC + +config ESWIN_RSV_MEMBLOCK + bool "ESWIN reserved memory block support" + depends on MMU + help + If reserved-memory has compatible = "eswin-reserve-memory" and + no-map properties, this memory block will be initialized and freed in + Eswin private buddy system. Using es_alloc_pages(memblock, order) to + alloc pages from this memory block and es_free_pages(memblock, page) to + free the pages to this memory block. + + If unsure, say "n". + +source "drivers/memory/eswin/codacache/Kconfig" + +endif diff --git a/drivers/memory/eswin/Makefile b/drivers/memory/eswin/Makefile new file mode 100644 index 000000000000..1b732b2a439d --- /dev/null +++ b/drivers/memory/eswin/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_ESWIN_MC) += eswin_cpuid_hartid_convert.o +obj-$(CONFIG_ESWIN_RSV_MEMBLOCK) += eswin_memblock.o +obj-$(CONFIG_ESWIN_CODACACHE_CONTROLLER) += codacache/ diff --git a/drivers/memory/eswin/buddy.h b/drivers/memory/eswin/buddy.h new file mode 100644 index 000000000000..e3c509a511c6 --- /dev/null +++ b/drivers/memory/eswin/buddy.h @@ -0,0 +1,226 @@ +#ifndef __BUDDY_H__ +#define __BUDDY_H__ + +#define RUN_IN_KERNEL 1 + +#ifdef RUN_IN_KERNEL +#include +#include +#include +#include +#include +#include + +// #define buddy_print(fmt...) printk(fmt) +#define buddy_print(fmt...) +#define BUDDY_BUG_ON(condition) WARN_ON(condition) + +#define buddy_spin_lock_init(lock) spin_lock_init(lock) +#define buddy_spin_lock(lock) spin_lock(lock) +#define buddy_spin_unlock(lock) spin_unlock(lock) +/* +#define es_spin_lock_init(esLock) spin_lock_init(esLock) +#define es_spin_lock(esLock) spin_lock(esLock) +#define es_spin_unlock(esLock) spin_unlock(esLock) +*/ +#define es_spin_lock_init(esLock) +#define es_spin_lock(esLock) +#define es_spin_unlock(esLock) +#else +#include "list.h" +#include //printf +#include //memset +#include //assert + +#define buddy_print(fmt...) printf(fmt) +#define BUDDY_BUG_ON(condition) assert(condition) + +#define buddy_spin_lock_init(lock) do {}while(0) +#define buddy_spin_lock(lock) do {}while(0) +#define buddy_spin_unlock(lock) do {}while(0) + +#define es_spin_lock_init(esLock) +#define es_spin_lock(esLock) +#define es_spin_unlock(esLock) +#endif +/* + * ���Page������״̬ + * */ +enum esPageflags_e{ + enPG_head, //����buddyϵͳ�ڣ��׸�ҳ + enPG_tail, //����buddyϵͳ�ڣ���ҳ֮���ҳ�� + enPG_buddy, //��buddyϵͳ�� +}; + +#define BUDDY_PAGE_SHIFT PAGE_SHIFT//(12UL) +#define BUDDY_PAGE_SIZE (1UL << BUDDY_PAGE_SHIFT) +#define BUDDY_MAX_ORDER MAX_ORDER // (10UL)//(9UL) + +struct esPage_s +{ + // spin_lock lock; + struct list_head lru; + unsigned long flags; + union { + unsigned long order; + struct esPage_s *first_page; + }; +}; + +struct es_free_area_s +{ + struct list_head free_list; + unsigned long nr_free; +}; + +struct mem_zone +{ +#ifdef RUN_IN_KERNEL + spinlock_t lock; +#endif + unsigned long page_num; + unsigned long page_size; + struct esPage_s *first_page; + unsigned long start_addr; + unsigned long end_addr; + struct es_free_area_s free_area[BUDDY_MAX_ORDER]; +}; + +#ifdef RUN_IN_KERNEL +#define BLOCK_MAX_NAME 64 +struct mem_block { +#ifdef RUN_IN_KERNEL + spinlock_t esLock; +#endif + struct mem_zone zone; + unsigned long page_num; + struct esPage_s *esPagesStart; + struct page *kPageStart; + char name[BLOCK_MAX_NAME]; +}; +#else +struct mem_block { + struct mem_zone zone; + struct esPage_s *pages; +}; +#endif + +void buddy_system_init(struct mem_zone *zone, + struct esPage_s *start_page, + unsigned long start_addr, + unsigned long page_num); +struct esPage_s *buddy_get_pages(struct mem_zone *zone, + unsigned long order); +void buddy_free_pages(struct mem_zone *zone, + struct esPage_s *page); +unsigned long buddy_num_free_page(struct mem_zone *zone); + +/* + * ҳ��Ϊ���ࣺһ���ǵ�ҳ��zero page��, + * һ�������ҳ��compound page���� + * ���ҳ�ĵ�һ����head������Ϊtail�� + * */ +static inline void __esSetPageHead(struct esPage_s *page) +{ + page->flags |= (1UL<flags |= (1UL<flags |= (1UL<flags &= ~(1UL<flags &= ~(1UL<flags &= ~(1UL<flags & (1UL<flags & (1UL<flags & (1UL<order = order; + __esSetPageBuddy(page); +} + +static inline void rmv_page_order_buddy(struct esPage_s *page) +{ + page->order = 0; + __esClearPageBuddy(page); +} + +/* + * ����buddyҳ + * */ +static inline unsigned long +__find_buddy_index(unsigned long page_idx, unsigned int order) +{ + return (page_idx ^ (1 << order)); +} + +static inline unsigned long +__find_combined_index(unsigned long page_idx, unsigned int order) +{ + return (page_idx & ~(1 << order)); +} + +/* + * Linux�ں˽����ҳ��order��¼�ڵڶ���ҳ���prevָ���� + * ��ϵͳ�����ҳ��order��¼���׸�ҳ���page->order���� + * */ +static inline unsigned long esCompound_order(struct esPage_s *page) +{ + if (!esPageHead(page)) + return 0; //��ҳ + //return (unsigned long)page[1].lru.prev; + return page->order; +} + +static inline void esSet_compound_order(struct esPage_s *page, unsigned long order) +{ + //page[1].lru.prev = (void *)order; + page->order = order; +} + +static inline void BUDDY_BUG(const char *f, int line) +{ + buddy_print("BUDDY_BUG in %s, %d.\n", f, line); + BUDDY_BUG_ON(1); +} + +// print buddy system status +void dump_print(struct mem_zone *zone); +void dump_print_dot(struct mem_zone *zone); + +#endif diff --git a/drivers/memory/eswin/codacache/Kconfig b/drivers/memory/eswin/codacache/Kconfig new file mode 100644 index 000000000000..104fdb4d08a2 --- /dev/null +++ b/drivers/memory/eswin/codacache/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 +config ESWIN_CODACACHE_CONTROLLER + bool "ESWIN codacache controller support" + help + The codacache, 4MB in total, could be entirely intialized as SPRAM, or partialy as + SPRAM and partilay as cache(i.e. Last Level Cache, LLC), or entirely as cache. + For example, if 2MB is initialized as SPRAM, then the reset of the codacache, 2MB + will be initialized as cache. The size of the SPRAM is determined by the reg size of + the spram node in dts. The below example shows that the codacache of 4MB is entirely + initialized as SPRAM. + npu0_reserved: sprammemory@59000000 { + reg = <0x0 0x59000000 0x0 0x400000>; + }; + + If unsure, say "n". + diff --git a/drivers/memory/eswin/codacache/Makefile b/drivers/memory/eswin/codacache/Makefile new file mode 100644 index 000000000000..f992e9a5eb89 --- /dev/null +++ b/drivers/memory/eswin/codacache/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +obj-$(CONFIG_ESWIN_CODACACHE_CONTROLLER) += llc_spram.o diff --git a/drivers/memory/eswin/codacache/llc_spram.c b/drivers/memory/eswin/codacache/llc_spram.c new file mode 100644 index 000000000000..8bd0912af4b7 --- /dev/null +++ b/drivers/memory/eswin/codacache/llc_spram.c @@ -0,0 +1,1576 @@ +/* + * ESWIN LLC_SPRAM on-chip SRAM allocation driver + * Copyright 2023, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0-only + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "llc_spram.h" + +#define HAVE_LLC_HARDWARE 1 + +MODULE_IMPORT_NS(DMA_BUF); + +#define DEVICE_NAME "llc_spram" + +#define SPRAM_GRANULARITY PAGE_SIZE + +static int npu_spram_size = 4 * 0x100000; //4M +module_param(npu_spram_size, int, 0644); +MODULE_PARM_DESC(npu_spram_size, "npu spram size"); + +struct platform_device *pdevs[2] = {NULL, NULL}; +const static uint32_t npu_llc_offset[2] = {NPU_LLC0_OFFSET, NPU_LLC1_OFFSET}; + +static const struct of_device_id spram_dt_ids[] = { + { .compatible = "eswin,llc" }, + {} +}; + +static struct llc_cache_ops llc_ops = { + .llc_flush_all = NULL, +}; + +struct llc_user { + struct list_head node; + const char *name; +}; + +struct llc_user_list { + struct device *dev; + atomic_t refcount; + struct mutex ref_lock; + struct list_head head; +}; + +static struct llc_user_list llc_user_lists[2]; + +struct spram_dev { + struct device *dev; + char *name; + void __iomem *virt_base; + phys_addr_t phys_addr; + struct gen_pool *pool; + void __iomem *npu_base; // The vaddr of the npu + int nid; + struct dma_heap *heap; + struct clk *aclk; + struct clk *cfg_clk; + struct clk *llc_clk; + struct clk *core_clk; + struct clk *mux_u_npu_core_3mux1_gfree; + struct clk *fixed_rate_clk_spll2_fout2; + struct reset_control *rstc_axi; + struct reset_control *rstc_cfg; + struct reset_control *rstc_core; + struct reset_control *rstc_llc; +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,6,0) +#define dma_buf_map iosys_map +#define dma_buf_map_set_vaddr iosys_map_set_vaddr +#define dma_buf_map_clear iosys_map_clear +#endif +#define spram_phys_to_virt(spram, phys) \ + (spram->virt_base + phys - spram->phys_addr) + +static struct llc_reg_base llc_base[MAX_LLC_CACHE_NODE_NUM]; + + +static void llc_reg_write(struct spram_dev *spram, uint32_t addr, uint32_t value) +{ + writel(value, spram->npu_base + addr); +} + +static uint32_t llc_reg_read(struct spram_dev *spram, uint32_t addr) +{ + return readl(spram->npu_base + addr); +} + +static void llc_write(struct spram_dev *spram, uint32_t device, uint32_t addr, uint32_t value) +{ + llc_reg_write(spram, npu_llc_offset[device] + addr, value); + dev_dbg(spram->dev, "%s:addr(0x%x)=0x%x\n", __func__, npu_llc_offset[device] + addr, value); +} + +static uint32_t llc_read(struct spram_dev *spram, uint32_t device, uint32_t addr) +{ + return llc_reg_read(spram, npu_llc_offset[device] + addr); +} + +static int llc_interleave_enable(struct spram_dev *spram) +{ + uint32_t regval, reg; + struct regmap *regmap; + struct device *dev = spram->dev; + int ret = 0; + + regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "eswin,syscfg"); + if (IS_ERR(regmap)) { + dev_err(dev, "No syscfg phandle specified\n"); + return PTR_ERR(regmap); + } + + ret = of_property_read_u32_index(dev->of_node, "eswin,syscfg", 1, ®); + if (ret) { + dev_err(dev, "can't get llc interleave enable reg offset(%d)\n", ret); + return ret; + } + + ret = regmap_read(regmap, reg, ®val); + if (ret) { + dev_err(dev, "failed to read llc interleave enable reg(%d)\n", ret); + return -EIO; + } + regval |= (1 << 0); + ret = regmap_write(regmap, reg, regval); + if (ret) { + dev_err(dev, "failed to write llc interleave enable reg(%d)\n", ret); + return -EIO; + } + + ret = regmap_read(regmap, reg, ®val); + if (!ret) { + dev_dbg(dev, "write, interleave reg_offset=0x%x, val=0x%x\n", reg, regval); + } + + return 0; + +} + +static int do_llc_spram_init(struct spram_dev *spram, uint32_t spram_size, uint32_t device) +{ + uint32_t val = 0; + uint32_t num_of_ways = 0; + uint32_t spram_num_of_ways = 0; + + dev_dbg(spram->dev, "---%s\n", __func__); + + //spramSzie must be intergral multiple of SIZE_OF_PER_WAY + if((spram_size > MAX_CACHE_SIZE) || (spram_size % SIZE_OF_PER_WAY)) { + dev_err(spram->dev,"Invalid spramSize\n"); + return -1; + } + + num_of_ways = MAX_CACHE_SIZE/SIZE_OF_PER_WAY; + spram_num_of_ways = spram_size / SIZE_OF_PER_WAY; + + llc_write(spram, device, CODA_CACHE_REG_CCUCMWVR, GENMASK_ULL(num_of_ways - 1, 0)); + llc_write(spram, device, CODA_CACHE_REG_CCUCMCR, 0x0); + do { + val = llc_read(spram, device, CODA_CACHE_REG_CCUCMAR); + msleep(1); + }while(val & 0x1); + + llc_write(spram, device, CODA_CACHE_REG_CCUCMCR, 0x10000); + do { + val = llc_read(spram, device, CODA_CACHE_REG_CCUCMAR); + msleep(1); + }while(val & 0x1); + + llc_write(spram, device, CODA_CACHE_REG_CCUSPBR0, 0); + llc_write(spram, device, CODA_CACHE_REG_CCUSPBR1, 0); + + if (spram_num_of_ways) { + llc_write(spram, device, CODA_CACHE_REG_CCUSPCR0, (spram_num_of_ways - 1) << 16); // num of ways are used as spram + /*number of cachelines, taking 2048 sets as an example*/ + llc_write(spram, device, CODA_CACHE_REG_CCUSPCR1, MAX_SETS * spram_num_of_ways - 1); + val = llc_read(spram, device, CODA_CACHE_REG_CCUSPCR0); + val |= 0x1; //enable Spram + llc_write(spram, device, CODA_CACHE_REG_CCUSPCR0, val); + } + + llc_write(spram, device, CODA_CACHE_REG_CCUCTCR, 0x3); // enable codacache ip lookups and fill + llc_write(spram, device, CODA_CACHE_REG_CCUUEDR, 0x3); // enable codacache ip error detection + + /* 0xbf0007:enable codacache ip write allocation partial + 0xff0007:enable codacache ip write-back Read and Write-allocate + */ + llc_write(spram, device, CODA_CACHE_REG_CCUCAOR, 0xff0007); + + return 0; +} + +static int llc_spram_init(struct spram_dev *spram) +{ + dev_dbg(spram->dev, "---%s\n", __func__); + + if (llc_interleave_enable(spram) < 0) + { + dev_err(spram->dev, "llc_interleave_enable error\n"); + return -1; + } + + if (do_llc_spram_init(spram, npu_spram_size / 2 , 0) < 0) + { + dev_err(spram->dev, "do_llc_spram_init0 error\n"); + return -1; + } + + if (do_llc_spram_init(spram, npu_spram_size / 2, 1) < 0) + { + dev_err(spram->dev, "do_llc_spram_init1 error\n"); + return -1; + } + + return 0; +} + +int llc_flush_operation(unsigned long start, unsigned long len) +{ + if (unlikely(!llc_ops.llc_flush_all)) { + pr_err("LLC cache ops is NULL!!!\n"); + return -1; + } + + llc_ops.llc_flush_all(start, len); + + return 0; +} +EXPORT_SYMBOL(llc_flush_operation); + +static void devm_llc_ops_unregister(struct device *dev, void *res) +{ + llc_ops.llc_flush_all = NULL; + dev_info(dev, "%s done!\n", __func__); +} + +static int devm_llc_ops_register(struct device *dev, llc_flush_all_t llc_flush_all) +{ + void *ptr; + + if (unlikely(!llc_flush_all)) + return -1; + + ptr = devres_alloc(devm_llc_ops_unregister, 0, GFP_KERNEL); + if (!ptr) + return -1; + + llc_ops.llc_flush_all = llc_flush_all; + + dev_info(dev, "%s, done sucessfully!\n", __func__); + devres_add(dev, ptr); + + return 0; +} + +#if defined(HAVE_LLC_HARDWARE) +static bool llc_maint_is_activity(onwhich_die_t node_id) +{ + if (((readl(llc_base[node_id].CodaCache0_RegBase + CODA_CACHE_REG_CCUCMAR) & 0x1) == 1) || (readl(llc_base[node_id].CodaCache0_RegBase + CODA_CACHE_REG_CCUCTAR) & 0x3)) + return true; + + if (((readl(llc_base[node_id].CodaCache1_RegBase + CODA_CACHE_REG_CCUCMAR) & 0x1) == 1) || (readl(llc_base[node_id].CodaCache1_RegBase + CODA_CACHE_REG_CCUCTAR) & 0x3)) + return true; + + return false; +} + + +void llc_flush_all(unsigned long start, unsigned long len) +{ + int node_id = 0; + + // mb(); /* sync */ + if (start >= CONFIG_RISCV_DIE0_CACHED_OFFSET && (start + len) <= (CONFIG_RISCV_DIE0_CACHED_OFFSET + CONFIG_RISCV_DIE0_MEM_MAX_SIZE)) { + node_id = LLC_CACHE_NODE_0; + }else if (start >= CONFIG_RISCV_DIE1_CACHED_OFFSET && (start + len) <= (CONFIG_RISCV_DIE1_CACHED_OFFSET + CONFIG_RISCV_DIE1_MEM_MAX_SIZE)) { + node_id = LLC_CACHE_NODE_1; + } + else if (start >= CONFIG_RISCV_INTERLEAVE_CACHED_OFFSET && (start + len) <= (CONFIG_RISCV_INTERLEAVE_CACHED_OFFSET + CONFIG_RISCV_INTERLEAVE_MEM_MAX_SIZE)) { + node_id = -1;; + } + else { + WARN(1, "llc: out of range: %lx(%lx), skip flush\n", + start, len); + return; + } + + if (node_id == -1) { + writeq(0x4, (llc_base[LLC_CACHE_NODE_0].CodaCache0_RegBase + CODA_CACHE_REG_CCUCMCR)); + writeq(0x4, (llc_base[LLC_CACHE_NODE_0].CodaCache1_RegBase + CODA_CACHE_REG_CCUCMCR)); + writeq(0x4, (llc_base[LLC_CACHE_NODE_1].CodaCache0_RegBase + CODA_CACHE_REG_CCUCMCR)); + writeq(0x4, (llc_base[LLC_CACHE_NODE_1].CodaCache1_RegBase + CODA_CACHE_REG_CCUCMCR)); + while (llc_maint_is_activity(LLC_CACHE_NODE_0)) { + ndelay(100); + } + while (llc_maint_is_activity(LLC_CACHE_NODE_1)) { + ndelay(100); + } + } + else { + writeq(0x4, (llc_base[node_id].CodaCache0_RegBase + CODA_CACHE_REG_CCUCMCR)); + writeq(0x4, (llc_base[node_id].CodaCache1_RegBase + CODA_CACHE_REG_CCUCMCR)); + while (llc_maint_is_activity(node_id)) { + ndelay(100); + } + } + pr_debug("---%s, node_id %d, start 0x%lx, len 0x%lx\n", __func__, node_id, start, len); +} +#else +static void llc_flush_all(unsigned long start, unsigned long len) +{ + pr_info("%s\n", __func__); + return; +} +#endif + +static void llc_user_init(struct spram_dev *spram) +{ + struct llc_user_list *llc_user_list = &llc_user_lists[spram->nid]; + + llc_user_list->dev = spram->dev; + atomic_set(&llc_user_list->refcount, 0); + mutex_init(&llc_user_list->ref_lock); + INIT_LIST_HEAD(&llc_user_list->head); + + dev_dbg(spram->dev, "%s\n", __func__); +} + +static void llc_user_unregister(struct device *user_dev, void *res) +{ + int nid = dev_to_node(user_dev); + struct llc_user *user, *tmp; + struct llc_user_list *llc_user_list = NULL; + + if (nid == NUMA_NO_NODE) { + #ifdef CONFIG_NUMA + dev_err(user_dev, "%s:%d, NUMA_NO_NODE\n", __func__, __LINE__); + return; + #else + dev_dbg(user_dev, "%s:%d, NUMA_NO_NODE, single DIE\n", __func__, __LINE__); + nid = 0; + #endif + } + llc_user_list = &llc_user_lists[nid]; + + mutex_lock(&llc_user_list->ref_lock); + list_for_each_entry_safe(user, tmp, &llc_user_list->head, node) { + if (0 == strcmp(user->name, dev_name(user_dev))) { + list_del(&user->node); + kfree(user); + atomic_sub(1, &llc_user_list->refcount); + dev_dbg(user_dev, "llc_user_unregistered!\n"); + break; + } + } + mutex_unlock(&llc_user_list->ref_lock); + + dev_dbg(user_dev, "%s done!\n", __func__); +} + +int llc_user_register(struct device *user_dev) +{ + struct device *dev; + int nid = dev_to_node(user_dev); + struct llc_user_list *llc_user_list = NULL; + struct llc_user *new_user = NULL; + int ret = 0; + void *ptr; + + if (nid == NUMA_NO_NODE) { + #ifdef CONFIG_NUMA + dev_err(user_dev, "%s:%d, NUMA_NO_NODE\n", __func__, __LINE__); + return -EFAULT; + #else + dev_dbg(user_dev, "%s:%d, NUMA_NO_NODE, single DIE\n", __func__, __LINE__); + nid = 0; + #endif + } + + llc_user_list = &llc_user_lists[nid]; + dev = llc_user_list->dev; + + mutex_lock(&llc_user_list->ref_lock); + new_user = kzalloc(sizeof(*new_user), GFP_KERNEL); + if (!new_user) { + dev_err(dev, "%s failed to alloc user for %s\n", __func__, dev_name(user_dev)); + ret = -ENOMEM; + goto llc_user_unlock; + } + new_user->name = dev_name(user_dev); + list_add_tail(&new_user->node, &llc_user_list->head); + atomic_add(1, &llc_user_list->refcount); + + ptr = devres_alloc(llc_user_unregister, 0, GFP_KERNEL); + if (!ptr) { + dev_err(dev, "%s devres_alloc failed for %s\n", __func__, dev_name(user_dev)); + kfree(new_user); + ret = -ENOMEM; + goto llc_user_unlock; + } + + devres_add(user_dev, ptr); + +llc_user_unlock: + mutex_unlock(&llc_user_list->ref_lock); + + return ret; +} +EXPORT_SYMBOL(llc_user_register); + +int npu_cfg_rst(int nid, bool enable) +{ + struct platform_device *pdev = pdevs[nid]; + struct spram_dev *spram; + int ret; + + if (NULL == pdev) { + pr_err("%s, Invalid node id:%d\n", __func__, nid); + return -EINVAL; + } + spram = platform_get_drvdata(pdev); + if (spram == NULL) + return -EINVAL; + + if (true == enable) { + /*reset npu cfg*/ + ret = reset_control_deassert(spram->rstc_cfg); + WARN_ON(0 != ret); + } + else + reset_control_assert(spram->rstc_cfg); + + return 0; +} +EXPORT_SYMBOL(npu_cfg_rst); + +int npu_core_rst(int nid, bool enable) +{ + struct platform_device *pdev = pdevs[nid]; + struct spram_dev *spram; + int ret; + + if (NULL == pdev) { + pr_err("%s, Invalid node id:%d\n", __func__, nid); + return -EINVAL; + } + spram = platform_get_drvdata(pdev); + if (spram == NULL) + return -EINVAL; + + if (true == enable) { + /*reset npu cfg*/ + ret = reset_control_deassert(spram->rstc_core); + WARN_ON(0 != ret); + } + else + reset_control_assert(spram->rstc_core); + + return 0; +} +EXPORT_SYMBOL(npu_core_rst); + +int llc_spram_avail_size(int nid, uint32_t *pSpramSize) +{ + struct platform_device *pdev = pdevs[nid]; + struct spram_dev *spram; + + if (NULL == pdev) { + pr_err("%s, Invalid node id:%d\n", __func__, nid); + return -EINVAL; + } + spram = platform_get_drvdata(pdev); + if (spram == NULL) + return -EINVAL; + + *pSpramSize = gen_pool_avail(spram->pool); + + return 0; +} +EXPORT_SYMBOL(llc_spram_avail_size); + +static int spram_proc_show(struct seq_file *m, void *v) +{ + struct spram_dev *spram = m->private; + int nid = spram->nid; + struct llc_user_list *llc_user_list = &llc_user_lists[nid]; + struct llc_user *user; + + seq_printf(m, "SRAM pool: %zu KiB, Available: %zu KiB\n", + gen_pool_size(spram->pool) / 1024, + gen_pool_avail(spram->pool) / 1024); +#if 1 + seq_printf(m, "LLC Users(%d): \n", atomic_read(&llc_user_list->refcount)); + list_for_each_entry(user, &llc_user_list->head, node) { + seq_printf(m, "%s\n", user->name); + } +#endif + return 0; +} + +static int __init proc_spram_init(struct spram_dev *spram) +{ + char proc_name[64]; + + sprintf(proc_name, "%s_info", spram->name); + dev_dbg(spram->dev, "%s, proc_name:%s\n", __func__, proc_name); + if (NULL == proc_create_single_data(proc_name, 0, NULL, spram_proc_show, spram)) { + return -1; + } + + return 0; +} + +static int llc_clk_init(struct platform_device *pdev) +{ + struct spram_dev *spram = platform_get_drvdata(pdev); + int ret = 0; + + if (spram == NULL) + return -EINVAL; + + spram->aclk = devm_clk_get(&pdev->dev, "aclk"); + if (IS_ERR(spram->aclk)) { + ret = PTR_ERR(spram->aclk); + spram->aclk = NULL; + dev_err(&pdev->dev, "failed to get aclk: %d\n", ret); + return ret; + } + + spram->cfg_clk = devm_clk_get(&pdev->dev, "cfg_clk"); + if (IS_ERR(spram->cfg_clk)) { + ret = PTR_ERR(spram->cfg_clk); + spram->cfg_clk = NULL; + dev_err(&pdev->dev, "failed to get cfg_clk: %d\n", ret); + return ret; + } + + spram->llc_clk = devm_clk_get(&pdev->dev, "llc_clk"); + if (IS_ERR(spram->llc_clk)) { + ret = PTR_ERR(spram->llc_clk); + spram->llc_clk = NULL; + dev_err(&pdev->dev, "failed to get llc_clk: %d\n", ret); + return ret; + } + + + + spram->core_clk = devm_clk_get(&pdev->dev, "core_clk"); + if (IS_ERR(spram->core_clk)) { + ret = PTR_ERR(spram->core_clk); + spram->core_clk = NULL; + dev_err(&pdev->dev, "failed to get core_clk: %d\n", ret); + return ret; + } + + spram->mux_u_npu_core_3mux1_gfree = devm_clk_get(&pdev->dev, "mux_u_npu_core_3mux1_gfree"); + if (IS_ERR(spram->mux_u_npu_core_3mux1_gfree)) { + ret = PTR_ERR(spram->mux_u_npu_core_3mux1_gfree); + dev_err(&pdev->dev, "failed to get mux_u_npu_core_3mux1_gfree: %d\n", ret); + return ret; + } + + spram->fixed_rate_clk_spll2_fout2 = devm_clk_get(&pdev->dev, "fixed_rate_clk_spll2_fout2"); + if (IS_ERR(spram->fixed_rate_clk_spll2_fout2)) { + ret = PTR_ERR(spram->fixed_rate_clk_spll2_fout2); + dev_err(&pdev->dev, "failed to get fixed_rate_clk_spll2_fout2: %d\n", ret); + return ret; + } + + return 0; +} + +static int llc_clk_enable(struct platform_device *pdev) +{ + struct spram_dev *spram = platform_get_drvdata(pdev); + int ret = 0; + + if (spram == NULL) + return -EINVAL; + + /*enable clk*/ + ret = clk_prepare_enable(spram->aclk); + if (ret) { + dev_err(&pdev->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); + return ret; + } + + ret = clk_prepare_enable(spram->llc_clk); + if (ret) { + dev_err(&pdev->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); + return ret; + } + + return 0; +} + +static int llc_rst_init(struct platform_device *pdev) +{ + struct spram_dev *spram = platform_get_drvdata(pdev); + + if (spram == NULL) + return -EINVAL; + + spram->rstc_axi = devm_reset_control_get_optional(&pdev->dev, "axi"); + if (IS_ERR_OR_NULL(spram->rstc_axi)) { + dev_err(&pdev->dev, "Failed to get cfg reset handle\n"); + return -EFAULT; + } + + spram->rstc_cfg = devm_reset_control_get_optional(&pdev->dev, "cfg"); + if (IS_ERR_OR_NULL(spram->rstc_cfg)) { + dev_err(&pdev->dev, "Failed to get llc reset handle\n"); + return -EFAULT; + } + + spram->rstc_core = devm_reset_control_get_optional(&pdev->dev, "core"); + if (IS_ERR_OR_NULL(spram->rstc_core)) { + dev_err(&pdev->dev, "Failed to get cfg reset handle\n"); + return -EFAULT; + } + + spram->rstc_llc = devm_reset_control_get_optional(&pdev->dev, "llc"); + if (IS_ERR_OR_NULL(spram->rstc_llc)) { + dev_err(&pdev->dev, "Failed to get llc reset handle\n"); + return -EFAULT; + } + + return 0; +} + +static int llc_clk_set_parent(struct platform_device *pdev) +{ + int ret; + struct spram_dev *spram = platform_get_drvdata(pdev); + + if (spram == NULL) + return -EINVAL; + + ret = clk_set_parent(spram->mux_u_npu_core_3mux1_gfree, spram->fixed_rate_clk_spll2_fout2); + if (ret){ + dev_err(&pdev->dev, "failed to set mux_u_npu_core_3mux1_gfree parent: %d\n", ret); + return ret; + } + + return 0; +} +static int llc_clk_set_frq(struct platform_device *pdev) +{ + int ret; + unsigned long rate = 0; + struct spram_dev *spram = platform_get_drvdata(pdev); + + if (spram == NULL) + return -EINVAL; + + rate = clk_round_rate(spram->aclk, NPU_ACLK_RATE); + ret = clk_set_rate(spram->aclk, rate); + if(ret != 0){ + dev_err(&pdev->dev, "failed to set aclk: %d\n", ret); + return ret; + } + + rate = clk_round_rate(spram->llc_clk, NPU_LLC_CLK_RATE); + ret = clk_set_rate(spram->llc_clk, rate); + if(ret != 0){ + dev_err(&pdev->dev, "failed to set llc_clk: %d\n", ret); + return ret; + } + + rate = clk_round_rate(spram->core_clk, NPU_CORE_CLK_RATE); + ret = clk_set_rate(spram->core_clk, rate); + if(ret != 0){ + dev_err(&pdev->dev, "failed to set core_clk: %d\n", ret); + return ret; + } + + return 0; +} + +static int llc_rst_deassert(struct platform_device *pdev) +{ + int ret = 0; + struct spram_dev *spram = platform_get_drvdata(pdev); + + if (spram == NULL) + return -EINVAL; + + /*reset npu bus*/ + ret = reset_control_deassert(spram->rstc_axi); + WARN_ON(0 != ret); + + /*reset npu core*/ + ret = reset_control_deassert(spram->rstc_core); + WARN_ON(0 != ret); + + /*reset npu llc*/ + ret = reset_control_deassert(spram->rstc_llc); + WARN_ON(0 != ret); + + /*reset npu cfg*/ + ret = reset_control_deassert(spram->rstc_cfg); + WARN_ON(0 != ret); + + return 0; +} + +static int llc_clk_rst_print(struct platform_device *pdev) +{ + uint32_t regval[5]; + struct regmap *regmap; + struct spram_dev *spram = platform_get_drvdata(pdev); + struct device *dev; + int ret = 0; + + if (spram == NULL) + return -EINVAL; + + dev = spram->dev; + regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "eswin,syscrg_csr"); + if (IS_ERR(regmap)) { + dev_err(dev, "No syscrg phandle specified\n"); + return PTR_ERR(regmap); + } + + ret = regmap_read(regmap, 0x178, ®val[0]); + if (ret) { + dev_err(dev, "%s:%d, failed to read reg(%d)\n", __func__, __LINE__, ret); + return -EIO; + } + + /* llc clken*/ + ret = regmap_read(regmap, 0x17c, ®val[1]); + if (ret) { + dev_err(dev, "%s:%d, failed to read reg(%d)\n", __func__, __LINE__, ret); + return -EIO; + } + + ret = regmap_read(regmap, 0x180, ®val[2]); + if (ret) { + dev_err(dev, "%s:%d, failed to read reg(%d)\n", __func__, __LINE__, ret); + return -EIO; + } + + ret = regmap_read(regmap, 0x184, ®val[3]); + if (ret) { + dev_err(dev, "%s:%d, failed to read reg(%d)\n", __func__, __LINE__, ret); + return -EIO; + } + + ret = regmap_read(regmap, 0x418, ®val[4]); + if (ret) { + dev_err(dev, "%s:%d, failed to read reg(%d)\n", __func__, __LINE__, ret); + return -EIO; + } + + dev_info(dev, "[0x178]=0x%08x [0x17c]=0x%08x [0x180]=0x%08x [0x184]=0x%08x [0x418]=0x%08x\n", + regval[0], regval[1], regval[2], regval[3],regval[4]); + + return 0; +} + +/* Release the reset signal to let llc run */ +static int llc_clk_rst_init(struct platform_device *pdev) +{ + int ret = 0; + + dev_dbg(&pdev->dev, "---%s\n", __func__); + + ret = llc_clk_init(pdev); + if(ret != 0){ + dev_err(&pdev->dev, "llc_clk_init error: %d\n", ret); + return ret; + } + + ret = llc_clk_set_parent(pdev); + if(ret != 0){ + dev_err(&pdev->dev, "llc_clk_set_parent error: %d\n", ret); + return ret; + } + + ret = llc_rst_init(pdev); + if(ret != 0){ + dev_err(&pdev->dev, "llc_rst_init error: %d\n", ret); + return ret; + } + + 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); + if(ret != 0){ + dev_err(&pdev->dev, "llc_clk_enable error: %d\n", ret); + return ret; + } + + llc_rst_deassert(pdev); + + llc_clk_rst_print(pdev); + dev_dbg(&pdev->dev, "%s done successfully!\n", __func__); + + return ret; +} + +static int llc_resource_parse(struct platform_device *pdev) +{ + struct spram_dev *spram = platform_get_drvdata(pdev); + struct device* dev = &pdev->dev; + struct resource *res; + struct resource res_spram; + struct device_node *spram_node; + int nid = dev_to_node(dev); + void __iomem *npu_base; + struct page *page = NULL; + phys_addr_t phys; + int ret = 0; + + dev_dbg(dev, "----%s:%d\n", __func__, __LINE__); + + #ifdef CONFIG_NUMA + nid = dev_to_node(dev); + if (nid == NUMA_NO_NODE) { + dev_err(dev, "%s:%d, numa-node-id was not defined!\n", __func__, __LINE__); + return -EFAULT; + } + #else + if (of_property_read_s32(dev->of_node, "numa-node-id", &nid)) { + dev_err(dev, "%s:%d, numa-node-id was not defined!\n", __func__, __LINE__); + return -EFAULT; + } + #endif + spram->nid = nid; + + spram_node = of_parse_phandle(dev->of_node, "spram-region", 0); + of_address_to_resource(spram_node, 0, &res_spram); + + if (npu_spram_size > resource_size(&res_spram)) { + dev_err(dev, "Invalid spram size(0x%x), max spram size is 0x%x\n", + npu_spram_size, (unsigned int)resource_size(&res_spram)); + ret = -EINVAL; + goto out_spram_region; + } + + dev_info(dev, "res_spram.start=0x%x, max_size=0x%x, configured size=0x%x\n", + (unsigned int)res_spram.start, + (unsigned int)resource_size(&res_spram), + npu_spram_size); + + /* add to memblock and reserve it */ + ret = memblock_reserve(res_spram.start, npu_spram_size); + if (ret) { + dev_err(dev, "Failed to reserve spram!!!\n"); + goto out_spram_region; + } + + spram->phys_addr = res_spram.start; + spram->virt_base = devm_ioremap(&pdev->dev, spram->phys_addr, npu_spram_size); + if (spram->virt_base == NULL) { + dev_err(dev, "failed to ioremap() spram-region\n"); + ret = -ENODEV; + goto out_spram_region; + } + dev_dbg(dev, "---%s:%d, spram->virt_base=0x%px\n", + __func__, __LINE__, spram->virt_base); + + page = phys_to_page(spram->phys_addr); + phys = page_to_phys(page); + dev_dbg(dev, "---%s:%d, spram->phys_addr=0x%x, phys_to_page->page_to_phys:0x%x\n", + __func__, __LINE__, (unsigned int)spram->phys_addr, (unsigned int)phys); + + dev_dbg(dev, "%s:%d,---page:0x%px\n", __func__, __LINE__, page); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dev_dbg(&pdev->dev, "npu_base resource phys_start=0x%llx, size=0x%llx\n", res->start, resource_size(res)); + npu_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (IS_ERR(npu_base)) { + dev_err(&pdev->dev, "could not map NPU registers\n"); + ret = PTR_ERR(npu_base); + goto out_spram_region; + } + spram->npu_base = npu_base; + + llc_base[nid].CodaCache0_RegBase = npu_base + NPU_LLC0_OFFSET; + llc_base[nid].CodaCache1_RegBase = npu_base + NPU_LLC1_OFFSET; + +out_spram_region: + of_node_put(spram_node); + + return ret; +} +struct spram_heap { + struct dma_heap *heap; + struct spram_dev *spram; +}; + +struct spram_heap_buffer { + struct spram_heap *heap; + struct list_head attachments; + struct mutex lock; + unsigned long len; + struct sg_table sg_table; + int vmap_cnt; + void *vaddr; +}; + +struct dma_heap_attachment { + struct device *dev; + /* For spram, sgt is useless infact, just to adapt to the dma-buf.c */ + struct sg_table *table; + phys_addr_t phys_addr; + struct list_head list; + bool mapped; +}; + +static struct sg_table *dup_sg_table(struct sg_table *table) +{ + struct sg_table *new_table; + int ret, i; + struct scatterlist *sg, *new_sg; + + new_table = kzalloc(sizeof(*new_table), GFP_KERNEL); + if (!new_table) + return ERR_PTR(-ENOMEM); + + ret = sg_alloc_table(new_table, table->orig_nents, GFP_KERNEL); + if (ret) { + kfree(new_table); + return ERR_PTR(-ENOMEM); + } + + new_sg = new_table->sgl; + for_each_sgtable_sg(table, sg, i) { + sg_set_page(new_sg, sg_page(sg), sg->length, sg->offset); + new_sg = sg_next(new_sg); + } + + return new_table; +} + +static int spram_heap_attach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct spram_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a; + struct sg_table *table; + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return -ENOMEM; + + table = dup_sg_table(&buffer->sg_table); + if (IS_ERR(table)) { + kfree(a); + return -ENOMEM; + } + + a->table = table; + a->dev = attachment->dev; + INIT_LIST_HEAD(&a->list); + a->mapped = false; + + attachment->priv = a; + + mutex_lock(&buffer->lock); + list_add(&a->list, &buffer->attachments); + mutex_unlock(&buffer->lock); + + return 0; +} + +static void spram_heap_detach(struct dma_buf *dmabuf, + struct dma_buf_attachment *attachment) +{ + struct spram_heap_buffer *buffer = dmabuf->priv; + struct dma_heap_attachment *a = attachment->priv; + + mutex_lock(&buffer->lock); + list_del(&a->list); + mutex_unlock(&buffer->lock); + + sg_free_table(a->table); + kfree(a->table); + kfree(a); +} + +static struct sg_table *spram_heap_map_dma_buf(struct dma_buf_attachment *attachment, + enum dma_data_direction direction) +{ + struct dma_heap_attachment *a = attachment->priv; + struct sg_table *table = a->table; + int ret; + + ret = dma_map_sgtable(attachment->dev, table, direction, DMA_ATTR_SKIP_CPU_SYNC); + if (ret) + return ERR_PTR(-ENOMEM); + + + a->mapped = true; + return table; +} + +static void spram_heap_unmap_dma_buf(struct dma_buf_attachment *attachment, + struct sg_table *table, + enum dma_data_direction direction) +{ + struct dma_heap_attachment *a = attachment->priv; + + a->mapped = false; + dma_unmap_sgtable(attachment->dev, table, direction, DMA_ATTR_SKIP_CPU_SYNC); +} + +static int spram_heap_dma_buf_begin_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + /* Do Nothing, because spram is uncached memory space */ + return 0; +} + +static int spram_heap_dma_buf_end_cpu_access(struct dma_buf *dmabuf, + enum dma_data_direction direction) +{ + /* Do Nothing, because spram is uncached memory space */ + return 0; +} + +static int spram_heap_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma) +{ + struct spram_heap_buffer *buffer = dmabuf->priv; + struct sg_table *table = &buffer->sg_table; + unsigned long addr = vma->vm_start; + struct sg_page_iter piter; + int ret; + + /* vm_private_data will be used by eswin-ipc-scpu.c to get iova and + by mmz_vb.c to retrieve mem node + */ + vma->vm_private_data = dmabuf; + + for_each_sgtable_page(table, &piter, vma->vm_pgoff) { + struct page *page = sg_page_iter_page(&piter); + ret = remap_pfn_range(vma, addr, page_to_pfn(page), PAGE_SIZE, + vma->vm_page_prot); + if (ret) + return ret; + addr += PAGE_SIZE; + if (addr >= vma->vm_end) + return 0; + } + return 0; +} + +static void *spram_heap_do_vmap(struct spram_heap_buffer *buffer) +{ + struct sg_table *table = &buffer->sg_table; + int npages = PAGE_ALIGN(buffer->len) / PAGE_SIZE; + struct page **pages = vmalloc(sizeof(struct page *) * npages); + struct page **tmp = pages; + struct page *page; + struct sg_page_iter piter; + void *vaddr; + + if (!pages) + return ERR_PTR(-ENOMEM); + + for_each_sgtable_page(table, &piter, 0) { + WARN_ON(tmp - pages >= npages); + *tmp++ = sg_page_iter_page(&piter); + page = sg_page_iter_page(&piter); + } + + vaddr = vmap(pages, npages, VM_MAP, PAGE_KERNEL); + vfree(pages); + + if (!vaddr) + return ERR_PTR(-ENOMEM); + + return vaddr; +} + +static int spram_heap_vmap(struct dma_buf *dmabuf, struct dma_buf_map *map) +{ + struct spram_heap_buffer *buffer = dmabuf->priv; + void *vaddr; + int ret = 0; + + mutex_lock(&buffer->lock); + if (buffer->vmap_cnt) { + buffer->vmap_cnt++; + dma_buf_map_set_vaddr(map, buffer->vaddr); + goto out; + } + + vaddr = spram_heap_do_vmap(buffer); + + if (IS_ERR(vaddr)) { + ret = PTR_ERR(vaddr); + goto out; + } + + buffer->vaddr = vaddr; + buffer->vmap_cnt++; + dma_buf_map_set_vaddr(map, buffer->vaddr); +out: + mutex_unlock(&buffer->lock); + + return ret; +} + +static void spram_heap_vunmap(struct dma_buf *dmabuf, struct dma_buf_map *map) +{ + struct spram_heap_buffer *buffer = dmabuf->priv; + + mutex_lock(&buffer->lock); + if (!--buffer->vmap_cnt) { + vunmap(buffer->vaddr); + buffer->vaddr = NULL; + } + mutex_unlock(&buffer->lock); + dma_buf_map_clear(map); +} + +static void spram_heap_dma_buf_release(struct dma_buf *dmabuf) +{ + struct spram_heap_buffer *buffer = dmabuf->priv; + struct sg_table *table; + struct spram_dev *spram = buffer->heap->spram; + struct scatterlist *sg; + int i, page_num = 0; + + table = &buffer->sg_table; + for_each_sgtable_sg(table, sg, i) { + struct page *page = sg_page(sg); + #ifdef WANT_PAGE_VIRTUAL + void *vaddr = page_address(page); + #else + void *vaddr = spram_phys_to_virt(spram, page_to_phys(page)); + #endif + gen_pool_free(spram->pool, (unsigned long)vaddr, PAGE_SIZE); + page_num++; + } + sg_free_table(table); + kfree(buffer); + pr_info("%s, ---buffer->len=0x%lx, freed size=0x%x, Available:0x%lx\n", + __func__, buffer->len, + (page_num << PAGE_SHIFT), gen_pool_avail(spram->pool)); + +} + +static const struct dma_buf_ops spram_heap_buf_ops = { + .attach = spram_heap_attach, + .detach = spram_heap_detach, + .map_dma_buf = spram_heap_map_dma_buf, + .unmap_dma_buf = spram_heap_unmap_dma_buf, + .begin_cpu_access = spram_heap_dma_buf_begin_cpu_access, + .end_cpu_access = spram_heap_dma_buf_end_cpu_access, + .mmap = spram_heap_mmap, + .vmap = spram_heap_vmap, + .vunmap = spram_heap_vunmap, + .release = spram_heap_dma_buf_release, +}; + +struct spram_page { + struct list_head lru; + struct page *page; +}; + +static int spram_noncontiguous_alloc(struct spram_dev *spram, size_t len, struct sg_table *table) +{ + struct gen_pool *pool = spram->pool; + struct list_head pages; + struct page *page; + struct scatterlist *sg; + unsigned long size_remaining = len; + phys_addr_t phys_addr; + void *vaddr; + unsigned int page_num; + struct spram_page *spram_pages, *spram_page, *tmp_spram_page; + int i, ret = -ENOMEM; + + page_num = size_remaining / PAGE_SIZE; + pr_info("%s, ---try to alloc len=0x%lx, Available:0x%lx\n", __func__, len, gen_pool_avail(spram->pool)); + + spram_pages = kzalloc(page_num * sizeof(struct spram_page), GFP_KERNEL); + if (!spram_pages) { + pr_err("unable to allocate memory.\n"); + return -ENOMEM; + } + spram_page = spram_pages; + + INIT_LIST_HEAD(&pages); + i = 0; + while (size_remaining > 0) { + /* + * Avoid trying to allocate memory if the process + * has been killed by SIGKILL + */ + if (fatal_signal_pending(current)) { + ret = -EINTR; + goto free_spram; + } + + vaddr = gen_pool_dma_alloc(pool, PAGE_SIZE, &phys_addr); + if (!vaddr) + goto free_spram; + + page = phys_to_page(phys_addr); + // pr_debug("---%s:%d, page_to_phys:0x%x,page:0x%px, spram_page:0x%px\n", + // __func__, __LINE__, (unsigned int)page_to_phys(page), page, spram_page); + /* page->virtual is used for recording the gen pool vaddr which is needed when releasing spram memory */ + #ifdef WANT_PAGE_VIRTUAL + page->virtual = vaddr; + set_page_address(page, vaddr); + #endif + + spram_page->page = page; + list_add_tail(&spram_page->lru, &pages); + size_remaining -= PAGE_SIZE; + i++; + spram_page++; + } + + if (sg_alloc_table(table, i, GFP_KERNEL)) + goto free_spram; + + sg = table->sgl; + list_for_each_entry_safe(spram_page, tmp_spram_page, &pages, lru) { + page = spram_page->page; + sg_set_page(sg, page, PAGE_SIZE, 0); + sg = sg_next(sg); + list_del(&spram_page->lru); + } + + kfree(spram_pages); + return 0; +free_spram: + list_for_each_entry_safe(spram_page, tmp_spram_page, &pages, lru) { + #ifdef WANT_PAGE_VIRTUAL + vaddr = page_address(page); + #else + page = spram_page->page; + vaddr = spram_phys_to_virt(spram, page_to_phys(page)); + #endif + gen_pool_free(pool, (unsigned long)vaddr, PAGE_SIZE); + } + kfree(spram_pages); + return ret; +} + +#if 0 +static int spram_contiguous_alloc(struct spram_dev *spram, size_t len, struct sg_table *table) +{ + struct gen_pool *pool = spram->pool; + int npages = PAGE_ALIGN(len) / PAGE_SIZE; + void *vaddr, *page_vaddr; + phys_addr_t phys_addr; + struct page *page; + struct scatterlist *sg; + int i, ret = -ENOMEM; + + vaddr = gen_pool_dma_alloc(pool, len, &phys_addr); + if (!vaddr) { + return ret; + } + + if (sg_alloc_table(table, npages, GFP_KERNEL)) + goto free_spram; + + page_vaddr = vaddr; + sg = table->sgl; + for(i = 0; i < npages; i++) { + page = phys_to_page(phys_addr); + /* page->virtual is used for recording the gen pool vaddr which is needed when + * releasing spram memory + */ + #ifdef WANT_PAGE_VIRTUAL + set_page_address(page, page_vaddr); + #endif + sg_set_page(sg, page, PAGE_SIZE, 0); + sg = sg_next(sg); + page_vaddr += PAGE_SIZE; + phys_addr += PAGE_SIZE; + } + + return 0; + +free_spram: + gen_pool_free(pool, (unsigned long)vaddr, len); + return ret; +} +#endif + +static struct dma_buf *spram_heap_allocate(struct dma_heap *heap, + unsigned long len, + unsigned long fd_flags, + unsigned long heap_flags) +{ + struct spram_heap *spram_heap = dma_heap_get_drvdata(heap); + struct spram_dev *spram = spram_heap->spram; + struct spram_heap_buffer *buffer; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + struct dma_buf *dmabuf; + struct sg_table *table; + struct scatterlist *sg; + int i, ret = -ENOMEM; + + if (!PAGE_ALIGNED(len)) { + dev_err(spram->dev, "Err, request len is NOT aligned with PAGE_SIZE\n"); + return ERR_PTR(-EINVAL); + } + + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&buffer->attachments); + mutex_init(&buffer->lock); + buffer->heap = spram_heap; + buffer->len = len; + + table = &buffer->sg_table; + + /* Todo: contiguous alloc flag is not permitted by dma-heap. */ +#if 0 + if ((heap_flags & DMA_HEAP_VALID_HEAP_FLAGS) == HEAP_FLAGS_SPRAM_FORCE_CONTIGUOUS) { + dev_dbg(spram->dev, "force contiguous allocation!\n"); + ret = spram_contiguous_alloc(spram, len, table); + } + else +#endif + { + dev_dbg(spram->dev, "non-contiguous allocation!\n"); + ret = spram_noncontiguous_alloc(spram, len, table); + } + + if (ret) { + dev_err(spram->dev, "failed to alloc spram, Errcode:%d\n", ret); + return ERR_PTR(ret); + } + + /* create the dmabuf */ + exp_info.exp_name = dma_heap_get_name(heap); + exp_info.ops = &spram_heap_buf_ops; + exp_info.size = buffer->len; + exp_info.flags = fd_flags; + exp_info.priv = buffer; + dmabuf = dma_buf_export(&exp_info); + if (IS_ERR(dmabuf)) { + ret = PTR_ERR(dmabuf); + goto free_pages; + } + + dev_dbg(spram->dev, "%s successfully!\n", __func__); + + return dmabuf; + +free_pages: + for_each_sgtable_sg(table, sg, i) { + struct page *page = sg_page(sg); + #ifdef WANT_PAGE_VIRTUAL + void *vaddr = page_address(page); + #else + void *vaddr = spram_phys_to_virt(spram, page_to_phys(page)); + #endif + gen_pool_free(spram->pool, (unsigned long)vaddr, PAGE_SIZE); + } + sg_free_table(table); + kfree(buffer); + + dev_err(spram->dev, "%s:%d, failed to alloc spram buffer, ret=%d\n", __func__, __LINE__, ret); + + return ERR_PTR(ret); +} + +static const struct dma_heap_ops spram_heap_ops = { + .allocate = spram_heap_allocate, +}; + +static int __add_spram_heap(struct spram_dev *spram, void *data) +{ + struct spram_heap *spram_heap; + struct dma_heap_export_info exp_info; + + spram_heap = devm_kzalloc(spram->dev, sizeof(*spram_heap), GFP_KERNEL); + if (!spram_heap) + return -ENOMEM; + spram_heap->spram = spram; + + exp_info.name = spram->name; + exp_info.ops = &spram_heap_ops; + exp_info.priv = spram_heap; + + dev_dbg(spram->dev, "%s:%d, spram->name:%s\n", __func__, __LINE__, spram->name); + + spram_heap->heap = dma_heap_add(&exp_info); + if (IS_ERR(spram_heap->heap)) { + int ret = PTR_ERR(spram_heap->heap); + + return ret; + } + + /* spram->heap is only for the purpose of deleting heap when driver removed */ + spram->heap = spram_heap->heap; + + dev_info(spram->dev, "%s, Done adding spram heap name:%s\n", __func__, exp_info.name); + + return 0; +} + +static int llc_probe(struct platform_device *pdev) +{ + struct spram_dev *spram; + int ret = 0; + + dev_info(&pdev->dev, "%s start!\n", __func__); + + spram = devm_kzalloc(&pdev->dev, sizeof(*spram), GFP_KERNEL); + if (!spram) + return -ENOMEM; + + spram->dev = &pdev->dev; + + platform_set_drvdata(pdev, spram); + + ret = llc_resource_parse(pdev); + if (ret) { + return ret; + } + + #if defined(CONFIG_RISCV) && defined(HAVE_LLC_HARDWARE) + /* Init llc controller */ + ret = llc_clk_rst_init(pdev); + if (ret) + return ret; + + ret = llc_spram_init(spram); + if (ret) { + return ret; + } + #endif + if (devm_llc_ops_register(&pdev->dev, llc_flush_all)) { + dev_err(&pdev->dev, "register llc ops failed!!!\n"); + return -EFAULT; + } + + /* Create spram pool */ + + spram->pool = devm_gen_pool_create(spram->dev, ilog2(SPRAM_GRANULARITY), + dev_to_node(spram->dev), NULL); + if (IS_ERR(spram->pool)) { + dev_err(spram->dev, "devm_gen_pool_create() failed!!!\n"); + return PTR_ERR(spram->pool); + } + ret = gen_pool_add_virt(spram->pool, (unsigned long)spram->virt_base, + spram->phys_addr, npu_spram_size, dev_to_node(spram->dev)); + if (ret < 0) { + dev_err(spram->dev, "gen_pool_add_virt failed with %d\n", ret); + return ret; + } + + if (spram->pool) + dev_info(spram->dev, "SRAM pool: %zu KiB @ vaddr 0x%px, phys 0x%x\n", + gen_pool_size(spram->pool) / 1024, spram->virt_base, (unsigned int)spram->phys_addr); + + // vaddr = gen_pool_dma_alloc(spram->pool, PAGE_SIZE, &dma); + // dev_info(spram->dev, "gen_pool_alloc, vaddr=0x%px, dma=0x%x\n", vaddr, dma); + + spram->name = devm_kasprintf(spram->dev, GFP_KERNEL, "%s%d", DEVICE_NAME, spram->nid); + ret = __add_spram_heap(spram, NULL); + if (ret) { + dev_err(spram->dev, "failed to add spram heap\n"); + return ret; + } + + llc_user_init(spram); + + proc_spram_init(spram); + + #ifdef WANT_PAGE_VIRTUAL + dev_dbg(&pdev->dev, "WANT_PAGE_VIRTUAL is defined!\n"); + #else + dev_dbg(&pdev->dev, "WANT_PAGE_VIRTUAL is NOT defined!\n"); + #endif + + #if defined(HAVE_LLC_HARDWARE) + dev_dbg(&pdev->dev, "HAVE_LLC_HARDWARE is defined!\n"); + #else + dev_dbg(&pdev->dev, "HAVE_LLC_HARDWARE is NOT defined!\n"); + #endif + + #if defined(CONFIG_RISCV) + dev_dbg(&pdev->dev, "CONFIG_RISCV is defined!\n"); + #else + dev_dbg(&pdev->dev, "CONFIG_RISCV is NOT defined!\n"); + #endif + + #if defined(CONFIG_RISCV) && defined(HAVE_LLC_HARDWARE) + dev_dbg(&pdev->dev, "CONFIG_RISCV && HAVE_LLC_HARDWARE is defined!\n"); + #else + dev_dbg(&pdev->dev, "CONFIG_RISCV && HAVE_LLC_HARDWARE is NOT defined!\n"); + #endif + + dev_info(&pdev->dev, "%s Done!\n", __func__); + + pdevs[spram->nid] = pdev; + + return 0; +} + +static const struct of_device_id llc_dt_ids[] = { + { .compatible = "eswin,llc" }, + {} +}; +MODULE_DEVICE_TABLE(of, llc_dt_ids); + +// static struct platform_driver llc_driver __initdata = { +static struct platform_driver llc_driver = { + .driver = { + .name = DEVICE_NAME, + .of_match_table = llc_dt_ids, + }, + .probe = llc_probe, +}; + +builtin_platform_driver(llc_driver); +MODULE_DESCRIPTION("ESWIN LLC driver"); +MODULE_AUTHOR("Lin MIn "); +MODULE_LICENSE("GPL"); diff --git a/drivers/memory/eswin/codacache/llc_spram.h b/drivers/memory/eswin/codacache/llc_spram.h new file mode 100644 index 000000000000..40dd35efec5c --- /dev/null +++ b/drivers/memory/eswin/codacache/llc_spram.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Defines for the LLC SPRAM driver + */ + +#ifndef __LLC_SPRAM_H +#define __LLC_SPRAM_H +#include + +// At least one way must be reserved for cache +#define MAX_CACHE_SIZE (2 * 0x100000) //2MB +#define MAX_NUM_OF_WAY_SET_ASSOCIATIVE 16 //16-way set associative, i.e. 16 lines per set +#define SIZE_OF_PER_WAY (MAX_CACHE_SIZE / MAX_NUM_OF_WAY_SET_ASSOCIATIVE) +#define CACHE_LINE_SIZE 128 + +// 8MB/16way/256 = 2048 sets +// 4MB/16way/128 = 2048 sets +#define MAX_SETS (MAX_CACHE_SIZE / MAX_NUM_OF_WAY_SET_ASSOCIATIVE/CACHE_LINE_SIZE) + +//At least one way must be reserved for cache +#define SPRAM_WAYS (MAX_NUM_OF_WAY_SET_ASSOCIATIVE - 1) +#define SPRAM_SIZE (SPRAM_WAYS * MAX_CACHE_SIZE / MAX_NUM_OF_WAY_SET_ASSOCIATIVE) //4MB of MAX_CACHE_SIZE is used as spram + +#define NPU_LLC0_OFFSET 0x188000 +#define NPU_LLC1_OFFSET 0x189000 + + +enum coda_cache_reg +{ + CODA_CACHE_REG_CCUTCR = 0x0000, + CODA_CACHE_REG_CCUTAR = 0x0004, + CODA_CACHE_REG_CCUCTCR = 0x0010, + CODA_CACHE_REG_CCUCTAR = 0x0014, + CODA_CACHE_REG_CCUCAOR = 0x0018, + CODA_CACHE_REG_CCUSPCR0 = 0x0020, + CODA_CACHE_REG_CCUSPCR1 = 0x0024, + CODA_CACHE_REG_CCUSPBR0 = 0x0028, + CODA_CACHE_REG_CCUSPBR1 = 0x002C, + CODA_CACHE_REG_CCUWPCR00 = 0x0040, + CODA_CACHE_REG_CCUWPCR10 = 0x0044, + CODA_CACHE_REG_CCUWPCR01 = 0x0048, + CODA_CACHE_REG_CCUWPCR11 = 0x004c, + CODA_CACHE_REG_CCUCMCR = 0x0100, + CODA_CACHE_REG_CCUCMAR = 0x0104, + CODA_CACHE_REG_CCUCMLR0 = 0x0108, + CODA_CACHE_REG_CCUCMLR1 = 0x010c, + CODA_CACHE_REG_CCUCMLR2 = 0x0110, + CODA_CACHE_REG_CCUCMDR = 0x0114, + CODA_CACHE_REG_CCUCMWVR = 0x0118, + CODA_CACHE_REG_CCUCECR = 0x0140, + CODA_CACHE_REG_CCUCESR = 0x0144, + CODA_CACHE_REG_CCUCESAR = 0x0148, + CODA_CACHE_REG_CCUCELR0 = 0x014c, + CODA_CACHE_REG_CCUCELR1 = 0x0150, + CODA_CACHE_REG_CCUUEDR = 0x0154, + CODA_CACHE_REG_CCUUEIR = 0x0158, + CODA_CACHE_REG_CCUUESR = 0x015c, + CODA_CACHE_REG_CCUUESAR = 0x0160, + CODA_CACHE_REG_CCUUELR0 = 0x0164, + CODA_CACHE_REG_CCUUELR1 = 0x0168, + CODA_CACHE_REG_CCUIDR = 0x01c0, + CODA_CACHE_REG_CCUCRTR = 0x01c4, + CODA_CACHE_REG_CCUESR = 0x01c8, + CODA_CACHE_REG_CCUEMR = 0x01cc, + CODA_CACHE_REG_CCUEAR = 0x01d0, +}; +typedef enum { + LLC_CACHE_NODE_0 = 0, + LLC_CACHE_NODE_1, + MAX_LLC_CACHE_NODE_NUM, +}onwhich_die_t; + +struct llc_reg_base { + void __iomem *CodaCache0_RegBase; + void __iomem *CodaCache1_RegBase; +}; + +/* llc cache operation */ +typedef void (*llc_flush_all_t)(unsigned long start, unsigned long len); +struct llc_cache_ops { + llc_flush_all_t llc_flush_all; +}; + +int llc_user_register(struct device *user_dev); +int npu_cfg_rst(int nid, bool enable); +int npu_core_rst(int nid, bool enable); +int llc_spram_avail_size(int nid, uint32_t *pSpramSize); + +int llc_flush_operation(unsigned long start, unsigned long len); +#endif \ No newline at end of file diff --git a/drivers/memory/eswin/eswin_cpuid_hartid_convert.c b/drivers/memory/eswin/eswin_cpuid_hartid_convert.c new file mode 100644 index 000000000000..cfa2d6462d74 --- /dev/null +++ b/drivers/memory/eswin/eswin_cpuid_hartid_convert.c @@ -0,0 +1,39 @@ +/* + * ESWIN eic770x cpu_nid and hart_id convert + * Copyright 2023, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0-only + * + * 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 +#include +#include +#include +#include +#include "eswin_cpuid_hartid_convert.h" + +unsigned long __eswin_cpuid_to_hartid_map[NR_CPUS] = { + [0 ... NR_CPUS-1] = INVALID_HARTID +}; +EXPORT_SYMBOL_GPL(__eswin_cpuid_to_hartid_map); + +static int __init eswin_cpuid_hartid_convert_init(void) +{ + int i; + + for (i = 0; i < NR_CPUS; i++) + eswin_cpuid_to_hartid_map(i) = cpuid_to_hartid_map(i); + + return 0; +} +arch_initcall(eswin_cpuid_hartid_convert_init); \ No newline at end of file diff --git a/drivers/memory/eswin/eswin_cpuid_hartid_convert.h b/drivers/memory/eswin/eswin_cpuid_hartid_convert.h new file mode 100644 index 000000000000..5bab0ea66f22 --- /dev/null +++ b/drivers/memory/eswin/eswin_cpuid_hartid_convert.h @@ -0,0 +1,32 @@ +/* + * ESWIN eic770x cpu_nid and hart_id convert + * Copyright 2023, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0-only + * + * 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 . + */ + +#ifndef __ESWIN_HARDID_CPUID_CONVERT_H +#define __ESWIN_HARDID_CPUID_CONVERT_H +#include + +#ifdef CONFIG_SMP +/* + * Mapping between linux logical cpu index and hartid. + */ +extern unsigned long __eswin_cpuid_to_hartid_map[NR_CPUS]; +#define eswin_cpuid_to_hartid_map(cpu) __eswin_cpuid_to_hartid_map[cpu] + +#endif + +#endif diff --git a/drivers/memory/eswin/eswin_memblock.c b/drivers/memory/eswin/eswin_memblock.c new file mode 100644 index 000000000000..c99b0b0b100d --- /dev/null +++ b/drivers/memory/eswin/eswin_memblock.c @@ -0,0 +1,170 @@ +/* + * eswin_rsvmem initializes the reserved memory in dst that has compatible = "eswin-reserve-memory" and + * no-map property. Each of these memory region will be treated as one memory block and managed by eswin + * buddy system. Users can allocate/frree pages from/to these memory blocks via es_alloc_pages/es_free_pages. + * + * Copyright 2023, Beijing ESWIN Computing Technology Co., Ltd.. All rights reserved. + * SPDX-License-Identifier: GPL-2.0-only + * + * 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 . + */ + +#define pr_fmt(fmt) "eswin_rsvmem: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "eswin_memblock.h" + + +struct mem_block eswin_rsvmem_blocks[MAX_ESWIN_RSVMEM_AREAS] = {0}; +unsigned eswin_rsvmem_block_count = 0; + +phys_addr_t eswin_rsvmem_get_base(const struct mem_block *memblock) +{ + return page_to_phys(memblock->kPageStart); +} + +unsigned long eswin_rsvmem_get_size(const struct mem_block *memblock) +{ + return memblock->page_num << PAGE_SHIFT; +} +EXPORT_SYMBOL(eswin_rsvmem_get_size); + +const char *eswin_rsvmem_get_name(const struct mem_block *memblock) +{ + return memblock->name; +} +EXPORT_SYMBOL(eswin_rsvmem_get_name); + +struct mem_block *eswin_rsvmem_get_memblock(const char *memBlkName) +{ + struct mem_block *memblock = NULL; + int i; + + for (i = 0; i < eswin_rsvmem_block_count; i++) { + if ((!strcmp(memBlkName, eswin_rsvmem_blocks[i].name)) && + (NULL != eswin_rsvmem_blocks[i].esPagesStart)){ + memblock = &eswin_rsvmem_blocks[i]; + break; + } + } + + return memblock; +} +EXPORT_SYMBOL(eswin_rsvmem_get_memblock); + +/** + * eswin_rsvmem_init_reserved_mem() - create eswin reserve memory from reserved memory + * @base: Base address of the reserved area + * @size: Size of the reserved area (in bytes), + * @name: The name of the area. + * + * This function creates eswin reserve memory block and manage it with eswin buddy allocator. + */ +static int __init eswin_rsvmem_init_reserved_mem(phys_addr_t base, phys_addr_t size, const char *name) +{ + struct mem_block *memblock; + phys_addr_t alignment; + + /* Sanity checks */ + if (eswin_rsvmem_block_count == ARRAY_SIZE(eswin_rsvmem_blocks)) { + pr_err("Not enough slots for eswin-reserve-memory!\n"); + return -ENOSPC; + } + + if (!size) { + pr_err("Invalid size 0x%llx\n", size); + return -EINVAL; + } + + /* ensure minimal alignment */ + alignment = PAGE_SIZE << + max_t(unsigned long, MAX_ORDER - 1, pageblock_order); + + if (ALIGN(base, alignment) != base || ALIGN(size, alignment) != size) { + pr_err("Alignment Err! base:0x%llx, size:0x%llx, alignment:0x%llx\n", base, size, alignment); + return -EINVAL; + } + + if (!name) { + pr_err("rsvmem block name is NULL!\n"); + return -EINVAL; + } + + memblock = &eswin_rsvmem_blocks[eswin_rsvmem_block_count]; + memblock->page_num = size >> PAGE_SHIFT; + + /* Set esPagesStart = NULL here, it will be allocated later by fs_initcall*/ + memblock->esPagesStart = NULL; + + memblock->kPageStart = phys_to_page(base); + snprintf(memblock->name, BLOCK_MAX_NAME, name); + + eswin_rsvmem_block_count++; + + return 0; +} + +int eswin_rsvmem_for_each_block(int (*it)(struct mem_block *rsvmem_block, void *data), void *data) +{ + int i; + + for (i = 0; i < eswin_rsvmem_block_count; i++) { + int ret = it(&eswin_rsvmem_blocks[i], data); + + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL(eswin_rsvmem_for_each_block); + +#ifdef CONFIG_OF_RESERVED_MEM +#include +#include +#include + +#undef pr_fmt +#define pr_fmt(fmt) fmt + +static int __init rmem_eswin_setup(struct reserved_mem *rmem) +{ + unsigned long node = rmem->fdt_node; + int err; + + if (of_get_flat_dt_prop(node, "reusable", NULL) || + !of_get_flat_dt_prop(node, "no-map", NULL)) + return -EINVAL; + + + err = eswin_rsvmem_init_reserved_mem(rmem->base, rmem->size, rmem->name); + if (err) { + pr_err("Reserved memory: unable to setup eswin reserve region, err=%d\n", err); + return err; + } + + pr_info("Reserved memory: created eswin reserve memory at %pa, size %ld MiB\n", + &rmem->base, (unsigned long)rmem->size / SZ_1M); + + return 0; +} +RESERVEDMEM_OF_DECLARE(eswin_rsvmem, "eswin-reserve-memory", rmem_eswin_setup); +#endif \ No newline at end of file diff --git a/drivers/memory/eswin/eswin_memblock.h b/drivers/memory/eswin/eswin_memblock.h new file mode 100644 index 000000000000..6c18444599de --- /dev/null +++ b/drivers/memory/eswin/eswin_memblock.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ESWIN_RSVMEM_H__ +#define __ESWIN_RSVMEM_H__ + +#include +#include +#include +#include "buddy.h" + +// #define QEMU_DEBUG 1 + +#define MAX_ESWIN_RSVMEM_AREAS (64) + +struct mem_block *eswin_rsvmem_get_memblock(const char *memBlkName); +int eswin_rsvmem_for_each_block(int (*it)(struct mem_block *rsvmem_block, void *data), void *data); +const char *eswin_rsvmem_get_name(const struct mem_block *memblock); + +#endif diff --git a/include/linux/eswin-win2030-sid-cfg.h b/include/linux/eswin-win2030-sid-cfg.h new file mode 100644 index 000000000000..c52268d06f7d --- /dev/null +++ b/include/linux/eswin-win2030-sid-cfg.h @@ -0,0 +1,12 @@ +#ifndef ESWIN_WIN2030_SID_CFG_H +#define ESWIN_WIN2030_SID_CFG_H + +int win2030_dynm_sid_enable(int nid); +int win2030_aon_sid_cfg(struct device *dev); +int win2030_tbu_power(struct device *dev, bool is_powerUp); +int win2030_tbu_power_by_dev_and_node(struct device *dev, struct device_node *node, bool is_powerUp); + +void trigger_waveform_start(void); +void trigger_waveform_stop(void); +void print_tcu_node_status(const char *call_name, int call_line); +#endif diff --git a/include/linux/eswin_npu.h b/include/linux/eswin_npu.h new file mode 100644 index 000000000000..d7f3c91491f1 --- /dev/null +++ b/include/linux/eswin_npu.h @@ -0,0 +1,21 @@ +/* + * ESWIN NPU Clock Rate Definitaions + * + * 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 "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __LINUX_ESWIN_NPU_H +#define __LINUX_ESWIN_NPU_H + +#define NPU_ACLK_RATE 800000000 +#define NPU_LLC_CLK_RATE 800000000 //nvdla +#define NPU_CORE_CLK_RATE 1040000000 //npu and e31 +#define NPU_E31_CLK_RATE 1040000000 //llc + +#endif /* __LINUX_ESWIN_NPU_H */ -- 2.47.0