kernel/0004-feat-eswin-memory-Added-eswin-memory-related-changes.patch

3198 lines
90 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

From 3e3aa7602d855e2ab0151ebd4b63c13fa2e78bfa Mon Sep 17 00:00:00 2001
From: linmin <linmin@eswincomputing.com>
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 = <WIN2030_TBUID_0xF00>;
- 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 = <WIN2030_TBUID_0xF00>;
/*
tbus = <WIN2030_TBUID_0x0>,
@@ -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 = <WIN2030_TBUID_DMA1>;
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 = <WIN2030_TBUID_ETH>;
+ 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 = <WIN2030_TBUID_ETH>;
+ 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 = <WIN2030_TBUID_DSP0>;
+ 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 = <WIN2030_TBUID_DSP1>;
+ 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 = <WIN2030_TBUID_DSP2>;
+ 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 = <WIN2030_TBUID_DSP3>;
+ 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 = <ESWIN_MAILBOX_U84_TO_DSP_0_REG_BASE>;
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 = <WIN2030_TBUID_PCIE>;
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 = <WIN2030_TBUID_VDEC>, <WIN2030_TBUID_JDEC>;
+ 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 = <WIN2030_TBUID_VENC>, <WIN2030_TBUID_JENC>;
+ 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 = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_SCPU_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & lpcpu*/
@@ -1082,6 +1096,7 @@ d0_mbox1: mbox@50a20000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_LPCPU_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & npu_0*/
@@ -1100,6 +1115,7 @@ d0_mbox2: mbox@50a40000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_NPU_0_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & npu_1*/
@@ -1118,6 +1134,7 @@ d0_mbox3: mbox@50a60000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_NPU_1_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & dsp_0*/
@@ -1136,6 +1153,7 @@ d0_mbox4: mbox@50a80000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_DSP_0_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & dsp_1*/
@@ -1154,6 +1172,7 @@ d0_mbox5: mbox@50aa0000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_DSP_1_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & dsp_2*/
@@ -1172,6 +1191,7 @@ d0_mbox6: mbox@50ac0000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_DSP_2_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & dsp_3*/
@@ -1190,6 +1210,7 @@ d0_mbox7: mbox@50ae0000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_DSP_3_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 = <WIN2030_TBUID_USB>;
+ dma-noncoherent;
};
};
@@ -2125,6 +2153,7 @@ d0_usbdrd_dwc3_1: dwc3@50490000 {
status = "disabled";
numa-node-id = <0>;
tbus = <WIN2030_TBUID_USB>;
+ dma-noncoherent;
};
};
@@ -2181,6 +2210,7 @@ isp_0: isp@0x51000000 {
tbus = <WIN2030_TBUID_ISP>;
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 = <WIN2030_TBUID_ISP>;
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 = <WIN2030_TBUID_0xF00>;
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 = <WIN2030_TBUID_DMA1>;
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 = <WIN2030_TBUID_VDEC>, <WIN2030_TBUID_JDEC>;
+ 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 = <WIN2030_TBUID_VENC>, <WIN2030_TBUID_JENC>;
+ 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 = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_SCPU_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 = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_LPCPU_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & npu_0*/
@@ -515,6 +524,7 @@ d1_mbox2: mbox@70a40000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_NPU_0_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & npu_1*/
@@ -533,6 +543,7 @@ d1_mbox3: mbox@70a60000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_NPU_1_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & dsp_0*/
@@ -551,6 +562,7 @@ d1_mbox4: mbox@70a80000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_DSP_0_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & dsp_1*/
@@ -569,6 +581,7 @@ d1_mbox5: mbox@70aa0000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_DSP_1_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & dsp_2*/
@@ -587,6 +600,7 @@ d1_mbox6: mbox@70ac0000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_DSP_2_IRQ_BIT>;
+ dma-noncoherent;
};
/*mailbox between u84 & dsp_3*/
@@ -605,6 +619,7 @@ d1_mbox7: mbox@70ae0000 {
reset-names = "rst", "rst_device";
lock-bit = <ESWIN_MAILBOX_WR_LOCK_BIT_U84>;
irq-bit = <ESWIN_MAIBOX_DSP_3_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 = <WIN2030_TBUID_DSP0>;
+ 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 = <WIN2030_TBUID_DSP1>;
+ 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 = <WIN2030_TBUID_DSP2>;
+ 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 = <WIN2030_TBUID_DSP3>;
+ 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 = <WIN2030_TBUID_PCIE>;
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 = <WIN2030_TBUID_ETH>;
+ 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 = <WIN2030_TBUID_ETH>;
+ 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 = <WIN2030_TBUID_USB>;
+ dma-noncoherent;
};
};
@@ -2070,6 +2108,7 @@ d1_usbdrd_dwc3_1: dwc3@70490000 {
status = "disabled";
numa-node-id = <1>;
tbus = <WIN2030_TBUID_USB>;
+ 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 <linux/mm.h>
+#include <linux/mm_types.h>
+#include <linux/bug.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+
+// #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 <stdio.h> //printf
+#include <string.h> //memset
+#include <assert.h> //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
+/*
+ * <20><><EFBFBD>Page<67><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬
+ * */
+enum esPageflags_e{
+ enPG_head, //<2F><><EFBFBD><EFBFBD>buddyϵͳ<CFB5>ڣ<EFBFBD><DAA3>׸<EFBFBD>ҳ
+ enPG_tail, //<2F><><EFBFBD><EFBFBD>buddyϵͳ<CFB5>ڣ<EFBFBD><DAA3><EFBFBD>ҳ֮<D2B3><D6AE><EFBFBD>ҳ<EFBFBD><D2B3>
+ enPG_buddy, //<2F><>buddyϵͳ<CFB5><CDB3>
+};
+
+#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);
+
+/*
+ * ҳ<><D2B3>Ϊ<EFBFBD><CEAA><EFBFBD>һ<E0A3BA><D2BB><EFBFBD>ǵ<EFBFBD>ҳ<EFBFBD><D2B3>zero page<67><65>,
+ * һ<><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>compound page<67><65><EFBFBD><EFBFBD>
+ * <20><><EFBFBD>ҳ<EFBFBD>ĵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>head<61><64><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊtail<69><6C>
+ * */
+static inline void __esSetPageHead(struct esPage_s *page)
+{
+ page->flags |= (1UL<<enPG_head);
+}
+
+static inline void __SetPageTail(struct esPage_s *page)
+{
+ page->flags |= (1UL<<enPG_tail);
+}
+
+static inline void __esSetPageBuddy(struct esPage_s *page)
+{
+ page->flags |= (1UL<<enPG_buddy);
+}
+/**/
+static inline void __esClearPageHead(struct esPage_s *page)
+{
+ page->flags &= ~(1UL<<enPG_head);
+}
+
+static inline void __ClearPageTail(struct esPage_s *page)
+{
+ page->flags &= ~(1UL<<enPG_tail);
+}
+
+static inline void __esClearPageBuddy(struct esPage_s *page)
+{
+ page->flags &= ~(1UL<<enPG_buddy);
+}
+/**/
+static inline int esPageHead(struct esPage_s *page)
+{
+ return (page->flags & (1UL<<enPG_head));
+}
+
+static inline int esPageTail(struct esPage_s *page)
+{
+ return (page->flags & (1UL<<enPG_tail));
+}
+
+static inline int esPageBuddy(struct esPage_s *page)
+{
+ return (page->flags & (1UL<<enPG_buddy));
+}
+
+/*
+ * <20><><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>order<65><72>PG_buddy<64><79>־
+ * */
+static inline void set_page_order_buddy(struct esPage_s *page, unsigned long order)
+{
+ page->order = order;
+ __esSetPageBuddy(page);
+}
+
+static inline void rmv_page_order_buddy(struct esPage_s *page)
+{
+ page->order = 0;
+ __esClearPageBuddy(page);
+}
+
+/*
+ * <20><><EFBFBD><EFBFBD>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<75>ں˽<DABA><CBBD><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>order<65><72>¼<EFBFBD>ڵڶ<DAB5><DAB6><EFBFBD>ҳ<EFBFBD><D2B3><EFBFBD>prevָ<76><D6B8><EFBFBD><EFBFBD>
+ * <20><>ϵͳ<CFB5><CDB3><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><D2B3>order<65><72>¼<EFBFBD><C2BC><EFBFBD>׸<EFBFBD>ҳ<EFBFBD><D2B3><EFBFBD>page->order<65><72><EFBFBD><EFBFBD>
+ * */
+static inline unsigned long esCompound_order(struct esPage_s *page)
+{
+ if (!esPageHead(page))
+ return 0; //<2F><>ҳ
+ //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 <https://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/reset.h>
+#include <linux/delay.h>
+#include <linux/genalloc.h>
+#include <linux/regmap.h>
+#include <linux/io.h>
+#include <linux/list_sort.h>
+#include <linux/dma-buf.h>
+#include <linux/dma-heap.h>
+#include <uapi/linux/dma-heap.h>
+#include <linux/dma-map-ops.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/mfd/syscon.h>
+#include <linux/memblock.h>
+#include <linux/version.h>
+
+#include <linux/eswin_npu.h>
+
+#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, &reg);
+ if (ret) {
+ dev_err(dev, "can't get llc interleave enable reg offset(%d)\n", ret);
+ return ret;
+ }
+
+ ret = regmap_read(regmap, reg, &regval);
+ 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, &regval);
+ 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, &regval[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, &regval[1]);
+ if (ret) {
+ dev_err(dev, "%s:%d, failed to read reg(%d)\n", __func__, __LINE__, ret);
+ return -EIO;
+ }
+
+ ret = regmap_read(regmap, 0x180, &regval[2]);
+ if (ret) {
+ dev_err(dev, "%s:%d, failed to read reg(%d)\n", __func__, __LINE__, ret);
+ return -EIO;
+ }
+
+ ret = regmap_read(regmap, 0x184, &regval[3]);
+ if (ret) {
+ dev_err(dev, "%s:%d, failed to read reg(%d)\n", __func__, __LINE__, ret);
+ return -EIO;
+ }
+
+ ret = regmap_read(regmap, 0x418, &regval[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 <linmin@eswincomputing.com>");
+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 <linux/io.h>
+
+// 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 <https://www.gnu.org/licenses/>.
+ */
+#include <linux/cpu.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#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 <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ESWIN_HARDID_CPUID_CONVERT_H
+#define __ESWIN_HARDID_CPUID_CONVERT_H
+#include <asm/smp.h>
+
+#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 <https://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) "eswin_rsvmem: " fmt
+
+#include <linux/memblock.h>
+#include <linux/err.h>
+#include <linux/mm.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/log2.h>
+#include <linux/highmem.h>
+#include <linux/io.h>
+#include <linux/kmemleak.h>
+#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 <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
+
+#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 <linux/init.h>
+#include <linux/types.h>
+#include <linux/numa.h>
+#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