3198 lines
90 KiB
Diff
3198 lines
90 KiB
Diff
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, ®);
|
||
+ 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 <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
|
||
|