Release v2.7.0
This commit is contained in:
@@ -69,7 +69,7 @@
|
||||
riscv,isa = "rv64imafdc_xtheadvector";
|
||||
riscv,isa-base = "rv64i";
|
||||
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", "zicntr", "zicsr",
|
||||
"zifencei", "zihpm", "xtheadvector";
|
||||
"zifencei", "zihpm", "xtheadvector", "xtheadsscofpmf";
|
||||
reg = <0>;
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-size = <65536>;
|
||||
@@ -105,7 +105,7 @@
|
||||
riscv,isa = "rv64imafdc_xtheadvector";
|
||||
riscv,isa-base = "rv64i";
|
||||
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", "zicntr", "zicsr",
|
||||
"zifencei", "zihpm", "xtheadvector";
|
||||
"zifencei", "zihpm", "xtheadvector", "xtheadsscofpmf";
|
||||
reg = <1>;
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-size = <65536>;
|
||||
@@ -139,7 +139,7 @@
|
||||
riscv,isa = "rv64imafdc_xtheadvector";
|
||||
riscv,isa-base = "rv64i";
|
||||
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", "zicntr", "zicsr",
|
||||
"zifencei", "zihpm", "xtheadvector";
|
||||
"zifencei", "zihpm", "xtheadvector", "xtheadsscofpmf";
|
||||
reg = <2>;
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-size = <65536>;
|
||||
@@ -173,7 +173,7 @@
|
||||
riscv,isa = "rv64imafdc_xtheadvector";
|
||||
riscv,isa-base = "rv64i";
|
||||
riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "v", "zicntr", "zicsr",
|
||||
"zifencei", "zihpm", "xtheadvector";
|
||||
"zifencei", "zihpm", "xtheadvector", "xtheadsscofpmf";
|
||||
reg = <3>;
|
||||
i-cache-block-size = <64>;
|
||||
i-cache-size = <65536>;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
dtb-$(CONFIG_ARCH_ZHIHE) += p100-emu.dtb p100-emu-d2d.dtb p100-evb.dtb
|
||||
dtb-$(CONFIG_ARCH_ZHIHE) += a210-emu.dtb a210-emu-d2d.dtb a210-evb.dtb
|
||||
@@ -1,13 +1,13 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include "p100-soc-core.dtsi"
|
||||
#include "p100-soc-peri.dtsi"
|
||||
#include "p100-soc-core-die1.dtsi"
|
||||
#include "p100-soc-peri-die1.dtsi"
|
||||
#include "p100-platform-emu.dtsi"
|
||||
#include "a210-soc-core.dtsi"
|
||||
#include "a210-soc-peri.dtsi"
|
||||
#include "a210-soc-core-die1.dtsi"
|
||||
#include "a210-soc-peri-die1.dtsi"
|
||||
#include "a210-platform-emu.dtsi"
|
||||
|
||||
/ {
|
||||
model = "P100 EMU configuration";
|
||||
model = "A210 EMU configuration";
|
||||
|
||||
aliases {
|
||||
serial0 = &uart0;
|
||||
@@ -70,7 +70,7 @@
|
||||
stdout-path = "serial4";
|
||||
};
|
||||
aon_subsys_die0_to_die1:aon_subsys_die0_to_die1 {
|
||||
compatible = "zhihe,p100-aon";
|
||||
compatible = "zhihe,a210-aon";
|
||||
mbox-names = "aon1";
|
||||
mboxes = <&mbox_920 2 0>;
|
||||
#mbox-cells = <2>;
|
||||
@@ -111,7 +111,7 @@
|
||||
};
|
||||
|
||||
&mbox_920 {
|
||||
compatible = "zhihe,p100-mbox";
|
||||
compatible = "zhihe,a210-mbox";
|
||||
reg = <0x00 0x00321000 0x0 0x1000>,
|
||||
<0x00 0x00320000 0x0 0x1000>,
|
||||
<0x00 0x00322000 0x0 0x1000>,
|
||||
@@ -1,11 +1,11 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include "p100-soc-core.dtsi"
|
||||
#include "p100-soc-peri.dtsi"
|
||||
#include "p100-platform-emu.dtsi"
|
||||
#include "a210-soc-core.dtsi"
|
||||
#include "a210-soc-peri.dtsi"
|
||||
#include "a210-platform-emu.dtsi"
|
||||
|
||||
/ {
|
||||
model = "P100 EMU configuration";
|
||||
model = "A210 EMU configuration";
|
||||
|
||||
aliases {
|
||||
serial0 = &uart0;
|
||||
@@ -1,8 +1,8 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include "p100-soc-core.dtsi"
|
||||
#include "p100-soc-peri.dtsi"
|
||||
#include "p100-platform-evb.dtsi"
|
||||
#include "a210-soc-core.dtsi"
|
||||
#include "a210-soc-peri.dtsi"
|
||||
#include "a210-platform-evb.dtsi"
|
||||
|
||||
#define SOUND_CARD_LINK(REG, FMT, CPU, M, CODEC, N) \
|
||||
simple-audio-card,dai-link@##REG { \
|
||||
@@ -17,7 +17,7 @@
|
||||
}
|
||||
|
||||
/ {
|
||||
model = "P100 EVB configuration";
|
||||
model = "A210 EVB configuration";
|
||||
|
||||
aliases {
|
||||
ethernet0 = &gmac0;
|
||||
@@ -1,8 +1,8 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include "p100-soc-core.dtsi"
|
||||
#include "p100-soc-peri.dtsi"
|
||||
#include "p100-platform-evb.dtsi"
|
||||
#include "a210-soc-core.dtsi"
|
||||
#include "a210-soc-peri.dtsi"
|
||||
#include "a210-platform-evb.dtsi"
|
||||
|
||||
#define SOUND_CARD_LINK(REG, FMT, CPU, M, CODEC, N) \
|
||||
simple-audio-card,dai-link@##REG { \
|
||||
@@ -17,7 +17,7 @@
|
||||
}
|
||||
|
||||
/ {
|
||||
model = "P100 EVB configuration";
|
||||
model = "A210 EVB configuration";
|
||||
|
||||
aliases {
|
||||
ethernet0 = &gmac0;
|
||||
@@ -1,8 +1,8 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include "p100-soc-core.dtsi"
|
||||
#include "p100-soc-peri.dtsi"
|
||||
#include "p100-platform-evb.dtsi"
|
||||
#include "a210-soc-core.dtsi"
|
||||
#include "a210-soc-peri.dtsi"
|
||||
#include "a210-platform-evb.dtsi"
|
||||
|
||||
#define SOUND_CARD_LINK(REG, FMT, CPU, M, CODEC, N) \
|
||||
simple-audio-card,dai-link@##REG { \
|
||||
@@ -17,7 +17,7 @@
|
||||
}
|
||||
|
||||
/ {
|
||||
model = "P100 EVB configuration";
|
||||
model = "A210 EVB configuration";
|
||||
|
||||
aliases {
|
||||
ethernet0 = &gmac0;
|
||||
@@ -295,16 +295,25 @@
|
||||
|
||||
&peri1_padctrl {
|
||||
gmac0_pins: gmac0-0 {
|
||||
txclk-pins {
|
||||
pins = "GPIO0_0"; /* GMAC0_TX_CLK */
|
||||
function = "gmac0";
|
||||
bias-disable;
|
||||
drive-strength = <13>;
|
||||
input-disable;
|
||||
input-schmitt-disable;
|
||||
slew-rate = <0>;
|
||||
};
|
||||
|
||||
tx-pins {
|
||||
pins = "GPIO0_0", /* GMAC0_TX_CLK */
|
||||
"GPIO0_2", /* GMAC0_TXEN */
|
||||
pins = "GPIO0_2", /* GMAC0_TXEN */
|
||||
"GPIO0_3", /* GMAC0_TXD0 */
|
||||
"GPIO0_4", /* GMAC0_TXD1 */
|
||||
"GPIO0_5", /* GMAC0_TXD2 */
|
||||
"GPIO0_6"; /* GMAC0_TXD3 */
|
||||
function = "gmac0";
|
||||
bias-disable;
|
||||
drive-strength = <25>;
|
||||
drive-strength = <20>;
|
||||
input-disable;
|
||||
input-schmitt-disable;
|
||||
slew-rate = <0>;
|
||||
@@ -319,7 +328,7 @@
|
||||
"GPIO0_11"; /* GMAC0_RXD3 */
|
||||
function = "gmac0";
|
||||
bias-disable;
|
||||
drive-strength = <1>;
|
||||
drive-strength = <13>;
|
||||
input-enable;
|
||||
input-schmitt-disable;
|
||||
slew-rate = <0>;
|
||||
@@ -414,7 +423,7 @@
|
||||
pins = "GPIO0_18", "GPIO0_20", "GPIO0_21", "GPIO0_22", "GPIO0_23";
|
||||
function = "qspi0";
|
||||
bias-disable;
|
||||
drive-strength = <7>;
|
||||
drive-strength = <13>;
|
||||
input-enable;
|
||||
input-schmitt-enable;
|
||||
slew-rate = <0>;
|
||||
@@ -469,7 +478,7 @@
|
||||
pins = "GPIO0_25";
|
||||
function = "can0";
|
||||
bias-disable;
|
||||
drive-strength = <25>;
|
||||
drive-strength = <5>;
|
||||
input-disable;
|
||||
input-schmitt-disable;
|
||||
slew-rate = <1>;
|
||||
@@ -501,7 +510,7 @@
|
||||
pins = "GPIO0_27";
|
||||
function = "can1";
|
||||
bias-disable;
|
||||
drive-strength = <25>;
|
||||
drive-strength = <5>;
|
||||
input-disable;
|
||||
input-schmitt-disable;
|
||||
slew-rate = <1>;
|
||||
@@ -572,21 +581,28 @@
|
||||
};
|
||||
};
|
||||
gmac1_pins: gmac1-0 {
|
||||
txclk-pins {
|
||||
pins = "GPIO1_2"; /* GMAC1_TX_CLK */
|
||||
function = "gmac1";
|
||||
bias-disable;
|
||||
drive-strength = <13>;
|
||||
input-disable;
|
||||
input-schmitt-disable;
|
||||
slew-rate = <0>;
|
||||
};
|
||||
tx-pins {
|
||||
pins = "GPIO1_2", /* GMAC1_TX_CLK */
|
||||
"GPIO1_4", /* GMAC1_TXEN */
|
||||
pins = "GPIO1_4", /* GMAC1_TXEN */
|
||||
"GPIO1_5", /* GMAC1_TXD0 */
|
||||
"GPIO1_6", /* GMAC1_TXD1 */
|
||||
"GPIO1_7", /* GMAC1_TXD2 */
|
||||
"GPIO1_8"; /* GMAC1_TXD3 */
|
||||
function = "gmac1";
|
||||
bias-disable;
|
||||
drive-strength = <25>;
|
||||
drive-strength = <20>;
|
||||
input-disable;
|
||||
input-schmitt-disable;
|
||||
slew-rate = <0>;
|
||||
};
|
||||
|
||||
rx-pins {
|
||||
pins = "GPIO1_3", /* GMAC1_RX_CLK */
|
||||
"GPIO1_9", /* GMAC1_RXDV */
|
||||
@@ -596,7 +612,7 @@
|
||||
"GPIO1_13"; /* GMAC1_RXD3 */
|
||||
function = "gmac1";
|
||||
bias-disable;
|
||||
drive-strength = <1>;
|
||||
drive-strength = <13>;
|
||||
input-enable;
|
||||
input-schmitt-disable;
|
||||
slew-rate = <0>;
|
||||
@@ -941,7 +957,7 @@
|
||||
pins = "GPIO3_1";
|
||||
function = "can2";
|
||||
bias-disable;
|
||||
drive-strength = <25>;
|
||||
drive-strength = <5>;
|
||||
input-disable;
|
||||
input-schmitt-disable;
|
||||
slew-rate = <1>;
|
||||
@@ -962,7 +978,7 @@
|
||||
pins = "GPIO3_2", "GPIO3_5", "GPIO3_6", "GPIO3_7", "GPIO3_8";
|
||||
function = "qspi1";
|
||||
bias-disable;
|
||||
drive-strength = <7>;
|
||||
drive-strength = <13>;
|
||||
input-enable;
|
||||
input-schmitt-enable;
|
||||
slew-rate = <0>;
|
||||
@@ -1066,16 +1082,14 @@
|
||||
&spi0 {
|
||||
cs-gpios = <&gpio0_porta 30 0>;
|
||||
rx-sample-delay-ns = <4>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spi0_pins>;
|
||||
spi-max-frequency = <55000000>;
|
||||
|
||||
spi_norflash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <55000000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <36000000>;
|
||||
w25q,fast-read;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
@@ -1083,33 +1097,35 @@
|
||||
&spi1 {
|
||||
cs-gpios = <&gpio2_porta 18 0>;
|
||||
rx-sample-delay-ns = <4>;
|
||||
spi-max-frequency = <55000000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spi1_pins>;
|
||||
|
||||
spi_norflash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <55000000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "jedec,spi-nor";
|
||||
reg = <0>;
|
||||
spi-max-frequency = <36000000>;
|
||||
w25q,fast-read;
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
&qspi0 {
|
||||
cs-gpios = <&gpio0_porta 19 0>;
|
||||
rx-sample-dly = <4>;
|
||||
rx-sample-dly = <2>;
|
||||
spi-swap-data = <1>;
|
||||
spi-max-frequency = <55000000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&qspi0_pins>;
|
||||
|
||||
spi_norflash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <55000000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
spi-tx-bus-width = <4>;
|
||||
spi-rx-bus-width = <4>;
|
||||
spi-max-frequency = <36000000>;
|
||||
reg = <0>;
|
||||
status = "okay";
|
||||
};
|
||||
@@ -1117,17 +1133,19 @@
|
||||
|
||||
&qspi1 {
|
||||
cs-gpios = <&gpio2_porta 29 0>;
|
||||
rx-sample-dly = <4>;
|
||||
rx-sample-dly = <2>;
|
||||
spi-swap-data = <1>;
|
||||
spi-max-frequency = <55000000>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&qspi1_pins>;
|
||||
|
||||
spi_norflash@0 {
|
||||
compatible = "jedec,spi-nor";
|
||||
spi-max-frequency = <55000000>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
spi-tx-bus-width = <4>;
|
||||
spi-rx-bus-width = <4>;
|
||||
spi-max-frequency = <36000000>;
|
||||
reg = <0>;
|
||||
status = "okay";
|
||||
|
||||
@@ -1149,22 +1167,6 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
spi-nandflash@1 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
compatible = "spi-nand";
|
||||
spi-max-frequency = <100000000>;
|
||||
spi-tx-bus-width = <4>;
|
||||
spi-rx-bus-width = <4>;
|
||||
reg = <1>;
|
||||
status = "disabled";
|
||||
|
||||
partition@0 {
|
||||
label = "nand1";
|
||||
reg = <0x00000000 0x08000000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
@@ -1663,10 +1665,10 @@
|
||||
GPMUX_SEL_07 -> 1
|
||||
GPMUX_SEL_08 -> 1
|
||||
*/
|
||||
// &spi0 {
|
||||
// pinctrl-names = "default";
|
||||
// pinctrl-0 = <&spi0_pins>;
|
||||
// };
|
||||
&spi0 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spi0_pins>;
|
||||
};
|
||||
|
||||
/*
|
||||
expansion IO: pwm2_ch5
|
||||
@@ -1696,71 +1698,6 @@
|
||||
pinctrl-0 = <&can1_pins>;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* FIXME: clk stages overlay to be selected for real SOC. */
|
||||
|
||||
/* bringup stage 3: full subsys + high freq */
|
||||
/* refer to maximum clk freq in p100-soc-core.dtsi */
|
||||
|
||||
/* bringup stage 2: full subsys + medium freq*/
|
||||
// &clk_peri {
|
||||
// peri1_spi_ssi_clk_frequency = <220000000>;
|
||||
// peri2_spi_ssi_clk_frequency = <220000000>;
|
||||
// peri1_qspi_ssi_clk_frequency = <220000000>;
|
||||
// peri2_qspi_ssi_clk_frequency = <220000000>;
|
||||
// uart_sclk_frequency = <24000000>;
|
||||
// emmc_ref_clk_frequency = <203076924>;
|
||||
// tee_clk_frequency = <200000000>;
|
||||
// };
|
||||
|
||||
// &clk_pcie {
|
||||
// pcie_ss_axi_m_aclk_frequency = <240000000>;
|
||||
// };
|
||||
|
||||
// &clk_npu {
|
||||
// npu_cclk_frequency = <600000000>;
|
||||
// npu_aclk_frequency = <600000000>;
|
||||
// };
|
||||
|
||||
// &emmc {
|
||||
// max-frequency = <49152000>;
|
||||
// };
|
||||
|
||||
// &sdhci0 {
|
||||
// max-frequency = <49152000>;
|
||||
// };
|
||||
|
||||
/* bringup stage 1: minisys + low freq */
|
||||
// &clk {
|
||||
// top_cfg_aclk_frequency = <165000000>;
|
||||
// top_pclk_frequency = <82500000>;
|
||||
// top_amux_clk_frequency = <240000000>;
|
||||
// iommu_ptw_aclk_frequency = <165000000>;
|
||||
// noc_cclk_frequency = <240000000>;
|
||||
// top_cpusys_bus_clk_frequency = <220000000>;
|
||||
// top_cpusys_pic_clk_frequency = <250000000>;
|
||||
// };
|
||||
|
||||
// &clk_peri {
|
||||
// peri1_spi_ssi_clk_frequency = <220000000>;
|
||||
// peri2_spi_ssi_clk_frequency = <220000000>;
|
||||
// peri1_qspi_ssi_clk_frequency = <220000000>;
|
||||
// peri2_qspi_ssi_clk_frequency = <220000000>;
|
||||
// uart_sclk_frequency = <24000000>;
|
||||
// emmc_ref_clk_frequency = <203076924>;
|
||||
// peri1_mst_aclk_frequency = <165000000>;
|
||||
// peri3_mst_aclk_frequency = <220000000>;
|
||||
// tee_clk_frequency = <200000000>;
|
||||
// };
|
||||
|
||||
// &emmc {
|
||||
// max-frequency = <49152000>;
|
||||
// };
|
||||
|
||||
// &sdhci0 {
|
||||
// max-frequency = <49152000>;
|
||||
// };
|
||||
|
||||
&vidmem {
|
||||
status = "okay";
|
||||
@@ -1,8 +1,8 @@
|
||||
/dts-v1/;
|
||||
|
||||
#include "p100-soc-core.dtsi"
|
||||
#include "p100-soc-peri.dtsi"
|
||||
#include "p100-platform-haps.dtsi"
|
||||
#include "a210-soc-core.dtsi"
|
||||
#include "a210-soc-peri.dtsi"
|
||||
#include "a210-platform-haps.dtsi"
|
||||
|
||||
#define SOUND_CARD_LINK(REG, FMT, CPU, M, CODEC, N) \
|
||||
simple-audio-card,dai-link@##REG { \
|
||||
@@ -17,7 +17,7 @@
|
||||
}
|
||||
|
||||
/ {
|
||||
model = "P100 HAPS configuration";
|
||||
model = "A210 HAPS configuration";
|
||||
|
||||
aliases {
|
||||
ethernet0 = &gmac0;
|
||||
@@ -222,6 +222,14 @@
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
&dm3x4 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&rp3x1 {
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
// &usb31_zhihe {
|
||||
// status = "disabled";
|
||||
// };
|
||||
@@ -3,8 +3,8 @@
|
||||
* Copyright (C) 2021 Alibaba Group Holding Limited.
|
||||
*/
|
||||
|
||||
#include <dt-bindings/clock/p100-clock.h>
|
||||
#include <dt-bindings/reset/p100-reset.h>
|
||||
#include <dt-bindings/clock/a210-clock.h>
|
||||
#include <dt-bindings/reset/a210-reset.h>
|
||||
#include <dt-bindings/iopmp/zh-iopmp.h>
|
||||
|
||||
/ {
|
||||
@@ -444,7 +444,7 @@
|
||||
#clock-cells = <1>;
|
||||
clocks = <&clk TOP_GPU_CORE_CLK_DIV>;
|
||||
clock-names = "top_gpu_core_clk";
|
||||
top_gpu_core_clk_frequency = <786432000>;
|
||||
top_gpu_core_clk_frequency = <792000000>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -560,15 +560,15 @@
|
||||
<&clk TOP_PERI_I2S_8CH0_SRC_CLK_MUX>, <&clk TOP_PERI_SPI_SSI_CLK0_DIV>,
|
||||
<&clk TOP_PERI_SPI_SSI_CLK1_DIV>, <&clk TOP_PERI_QSPI_SSI_CLK_MUX0>,
|
||||
<&clk TOP_PERI_QSPI_SSI_CLK_MUX1>, <&clk TOP_PERI_PDM_MCLK_DIV>,
|
||||
<&clk TOP_UART_SCLK_MUX>, <&clk TOP_PERI_TDM_SRC_CLK_MUX>,
|
||||
<&clk TOP_PAD_SENSOR_VCLK0_DIV>, <&clk TOP_PAD_SENSOR_VCLK1_DIV>,
|
||||
<&clk TOP_PERI_HIRES_CLK0_DIV>, <&clk TOP_PERI_HIRES_CLK1_DIV>,
|
||||
<&clk TOP_TEE_CLK_DIV>, <&clk TOP_PERI_EMMC_REF_CLK_DIV>,
|
||||
<&clk TOP_PERI_MST_ACLK0_DIV>, <&clk TOP_PERI_MST_CLK1_DIV>;
|
||||
<&clk TOP_PERI_TDM_SRC_CLK_MUX>, <&clk TOP_PAD_SENSOR_VCLK0_DIV>,
|
||||
<&clk TOP_PAD_SENSOR_VCLK1_DIV>, <&clk TOP_PERI_HIRES_CLK0_DIV>,
|
||||
<&clk TOP_PERI_HIRES_CLK1_DIV>, <&clk TOP_TEE_CLK_DIV>,
|
||||
<&clk TOP_PERI_EMMC_REF_CLK_DIV>, <&clk TOP_PERI_MST_ACLK0_DIV>,
|
||||
<&clk TOP_PERI_MST_CLK1_DIV>;
|
||||
clock-names = "peri0_timer_clk", "peri1_i2s0_src_clk", "peri2_i2s1_src_clk",
|
||||
"peri2_i2s2_src_clk", "peri2_i2s3_src_clk", "peri1_spi_ssi_clk",
|
||||
"peri2_spi_ssi_clk", "peri1_qspi_ssi_clk", "peri2_qspi_ssi_clk",
|
||||
"peri1_pdm_mclk", "uart_sclk", "peri1_tdm_src_clk",
|
||||
"peri1_pdm_mclk", "peri1_tdm_src_clk",
|
||||
"top_pad_sensor_vclk0_div", "top_pad_sensor_vclk1_div", "peri1_hires_clk",
|
||||
"peri2_hires_clk", "tee_clk", "emmc_ref_clk",
|
||||
"peri1_mst_aclk", "peri3_mst_aclk";
|
||||
@@ -582,7 +582,6 @@
|
||||
peri1_qspi_ssi_clk_frequency = <421478400>;
|
||||
peri2_qspi_ssi_clk_frequency = <421478400>;
|
||||
peri1_pdm_mclk_frequency = <31610880>;
|
||||
uart_sclk_frequency = <24000000>;
|
||||
peri1_tdm_src_clk_frequency = <316108800>;
|
||||
top_pad_sensor_vclk0_div_frequency = <74250000>;
|
||||
top_pad_sensor_vclk1_div_frequency = <148500000>;
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/p100-clock.h>
|
||||
#include <dt-bindings/clock/a210-clock.h>
|
||||
|
||||
/ {
|
||||
soc {
|
||||
@@ -85,7 +85,7 @@
|
||||
status = "okay";
|
||||
};
|
||||
mbox_920_die1: mbox@2000320000 {
|
||||
compatible = "zhihe,p100-mbox";
|
||||
compatible = "zhihe,a210-mbox";
|
||||
reg = <0x20 0x00321000 0x0 0x1000>, //mailbox1的中断通道
|
||||
<0x20 0x00320000 0x0 0x1000>,
|
||||
<0x20 0x00322000 0x0 0x1000>,
|
||||
@@ -103,14 +103,14 @@
|
||||
status = "okay";
|
||||
};
|
||||
aon_die1_to_die0: aon_subsys_die1_to_die0 {
|
||||
compatible = "zhihe,p100-aon";
|
||||
compatible = "zhihe,a210-aon";
|
||||
mbox-names = "aon2";
|
||||
mboxes = <&mbox_920_die1 1 0>; //parent / channel / type
|
||||
#mbox-cells = <2>;
|
||||
status = "okay";
|
||||
};
|
||||
aon_die1_to_die1: aon_subsys_die1_to_die1 {
|
||||
compatible = "zhihe,p100-aon";
|
||||
compatible = "zhihe,a210-aon";
|
||||
mbox-names = "aon3";
|
||||
mboxes = <&mbox_920_die1 1 0>;
|
||||
#mbox-cells = <2>;
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <dt-bindings/i2c/i2c.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/p100-clock.h>
|
||||
#include <dt-bindings/clock/a210-clock.h>
|
||||
#include <dt-bindings/iommu/zh-iommu.h>
|
||||
#include <dt-bindings/ata/ahci.h>
|
||||
|
||||
@@ -180,12 +180,12 @@
|
||||
};
|
||||
|
||||
can0: flexcan@2000000 {
|
||||
compatible = "fsl,a210-flexcan";
|
||||
compatible = "fsl,zha210-flexcan";
|
||||
reg = <0x00 0x2000000 0x0 0x4000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <261>;
|
||||
clocks = <&clk_peri PERI1_CAN0_HIRES_CLK_EN>,
|
||||
<&clk_peri PERI1_CAN0_OSC_CLK_EN>;
|
||||
<&clk_peri PERI1_CAN0_PCLK_EN>;
|
||||
clock-names = "ipg", "per";
|
||||
power-domains = <&power_peri1>;
|
||||
/* fsl,stop-mode = <&gpr 0x34 29 0x10 18>; */
|
||||
@@ -193,12 +193,12 @@
|
||||
};
|
||||
|
||||
can1: flexcan@2004000 {
|
||||
compatible = "fsl,a210-flexcan";
|
||||
compatible = "fsl,zha210-flexcan";
|
||||
reg = <0x00 0x2004000 0x0 0x4000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <262>;
|
||||
clocks = <&clk_peri PERI1_CAN1_HIRES_CLK_EN>,
|
||||
<&clk_peri PERI1_CAN1_OSC_CLK_EN>;
|
||||
<&clk_peri PERI1_CAN1_PCLK_EN>;
|
||||
clock-names = "ipg", "per";
|
||||
power-domains = <&power_peri1>;
|
||||
/* fsl,stop-mode = <&gpr 0x34 29 0x10 18>; */
|
||||
@@ -206,12 +206,12 @@
|
||||
};
|
||||
|
||||
can2: flexcan@8420000 {
|
||||
compatible = "fsl,a210-flexcan";
|
||||
compatible = "fsl,zha210-flexcan";
|
||||
reg = <0x00 0x8420000 0x0 0x4000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <263>;
|
||||
clocks = <&clk_peri PERI2_CAN2_HIRES_CLK_EN>,
|
||||
<&clk_peri PERI2_CAN2_OSC_CLK_EN>;
|
||||
<&clk_peri PERI2_CAN2_PCLK_EN>;
|
||||
clock-names = "ipg", "per";
|
||||
power-domains = <&power_peri2>;
|
||||
/* fsl,stop-mode = <&gpr 0x34 29 0x10 18>; */
|
||||
@@ -278,7 +278,6 @@
|
||||
power-domains = <&power_peri1>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
hw-flow-control = "unsupport";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -292,7 +291,6 @@
|
||||
power-domains = <&power_peri1>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
hw-flow-control = "unsupport";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -306,7 +304,6 @@
|
||||
power-domains = <&power_peri1>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
hw-flow-control = "unsupport";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -320,7 +317,6 @@
|
||||
power-domains = <&power_peri1>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
hw-flow-control = "unsupport";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -334,7 +330,6 @@
|
||||
power-domains = <&power_peri2>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
hw-flow-control = "unsupport";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -348,7 +343,6 @@
|
||||
power-domains = <&power_peri2>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
hw-flow-control = "unsupport";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -362,7 +356,6 @@
|
||||
power-domains = <&power_peri2>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
hw-flow-control = "unsupport";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -376,7 +369,6 @@
|
||||
power-domains = <&power_peri2>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
hw-flow-control = "unsupport";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -390,7 +382,6 @@
|
||||
power-domains = <&power_peri2>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
hw-flow-control = "unsupport";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -404,7 +395,6 @@
|
||||
power-domains = <&power_peri2>;
|
||||
reg-shift = <2>;
|
||||
reg-io-width = <4>;
|
||||
hw-flow-control = "unsupport";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@@ -424,9 +414,8 @@
|
||||
reg = <0x00 0x02023000 0x0 0x1000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <310>;
|
||||
clocks = <&clk_peri PERI1_SPI0_SSI_CLK_EN>,
|
||||
<&clk_peri PERI1_SPI0_PCLK_EN>;
|
||||
clock-names = "sclk", "pclk";
|
||||
clocks = <&clk_peri PERI1_SPI0_SSI_CLK_EN>;
|
||||
clock-names = "sclk";
|
||||
power-domains = <&power_peri1>;
|
||||
dmas = <&dmac0 9>, <&dmac0 8>;
|
||||
dma-names = "tx", "rx";
|
||||
@@ -444,9 +433,8 @@
|
||||
reg = <0x00 0x08413000 0x0 0x1000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <311>;
|
||||
clocks = <&clk_peri PERI2_SPI1_SSI_CLK_EN>,
|
||||
<&clk_peri PERI2_SPI1_PCLK_EN>;
|
||||
clock-names = "sclk", "pclk";
|
||||
clocks = <&clk_peri PERI2_SPI1_SSI_CLK_EN>;
|
||||
clock-names = "sclk";
|
||||
power-domains = <&power_peri2>;
|
||||
dmas = <&dmac0 62>, <&dmac0 61>;
|
||||
dma-names = "tx", "rx";
|
||||
@@ -464,9 +452,8 @@
|
||||
reg = <0x00 0x01000000 0x0 0x4000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <308>;
|
||||
clocks = <&clk_peri PERI1_QSPI0_SSI_CLK_EN>,
|
||||
<&clk_peri PERI1_QSPI0_PCLK_EN>;
|
||||
clock-names = "sclk", "pclk";
|
||||
clocks = <&clk_peri PERI1_QSPI0_SSI_CLK_EN>;
|
||||
clock-names = "sclk";
|
||||
power-domains = <&power_peri1>;
|
||||
num-cs = <2>;
|
||||
#address-cells = <1>;
|
||||
@@ -479,9 +466,8 @@
|
||||
reg = <0x00 0x08428000 0x0 0x4000>;
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <309>;
|
||||
clocks = <&clk_peri PERI2_QSPI1_SSI_CLK_EN>,
|
||||
<&clk_peri PERI2_QSPI1_PCLK_EN>;
|
||||
clock-names = "sclk", "pclk";
|
||||
clocks = <&clk_peri PERI2_QSPI1_SSI_CLK_EN>;
|
||||
clock-names = "sclk";
|
||||
power-domains = <&power_peri2>;
|
||||
num-cs = <2>;
|
||||
#address-cells = <1>;
|
||||
@@ -1552,7 +1538,7 @@
|
||||
};
|
||||
|
||||
mbox_920: mbox@0000310000 {
|
||||
compatible = "zhihe,p100-mbox";
|
||||
compatible = "zhihe,a210-mbox";
|
||||
reg = <0x00 0x00321000 0x0 0x1000>,
|
||||
<0x00 0x00320000 0x0 0x1000>,
|
||||
<0x00 0x00311000 0x0 0x1000>;
|
||||
@@ -1566,7 +1552,7 @@
|
||||
status = "okay";
|
||||
};
|
||||
aon: aon_subsys {
|
||||
compatible = "zhihe,p100-aon";
|
||||
compatible = "zhihe,a210-aon";
|
||||
mbox-names = "aon0";
|
||||
mboxes = <&mbox_920 1 0>; //parent / channel / type
|
||||
#mbox-cells = <2>;
|
||||
@@ -199,4 +199,4 @@ CONFIG_DEBUG_ATOMIC_SLEEP=y
|
||||
# CONFIG_RCU_TRACE is not set
|
||||
# CONFIG_FTRACE is not set
|
||||
# CONFIG_RUNTIME_TESTING_MENU is not set
|
||||
CONFIG_P100_BMU=y
|
||||
CONFIG_A210_BMU=y
|
||||
@@ -150,7 +150,7 @@ CONFIG_UDMABUF=y
|
||||
CONFIG_DMABUF_SELFTESTS=m
|
||||
# CONFIG_VIRTIO_MENU is not set
|
||||
# CONFIG_VHOST_MENU is not set
|
||||
CONFIG_CLK_P100=y
|
||||
CONFIG_CLK_A210=y
|
||||
CONFIG_HWSPINLOCK=y
|
||||
CONFIG_RISCV_IOMMU=y
|
||||
CONFIG_RESET_CONTROLLER=y
|
||||
@@ -194,4 +194,4 @@ CONFIG_DEBUG_ATOMIC_SLEEP=y
|
||||
# CONFIG_RCU_TRACE is not set
|
||||
# CONFIG_FTRACE is not set
|
||||
# CONFIG_RUNTIME_TESTING_MENU is not set
|
||||
CONFIG_P100_BMU=y
|
||||
CONFIG_A210_BMU=y
|
||||
@@ -160,7 +160,7 @@ CONFIG_SPI_DW_MMIO=y
|
||||
CONFIG_SPI_SPIDEV=y
|
||||
# CONFIG_PTP_1588_CLOCK is not set
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCTRL_P100=y
|
||||
CONFIG_PINCTRL_A210=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
CONFIG_GPIO_DWAPB=y
|
||||
CONFIG_SENSORS_MR75203=y
|
||||
@@ -174,6 +174,7 @@ CONFIG_WATCHDOG_PRETIMEOUT_GOV_NOOP=m
|
||||
CONFIG_WATCHDOG_PRETIMEOUT_GOV_PANIC=m
|
||||
CONFIG_WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP=y
|
||||
CONFIG_DW_WATCHDOG=y
|
||||
CONFIG_A210_WATCHDOG=y
|
||||
CONFIG_REGULATOR=y
|
||||
CONFIG_REGULATOR_FIXED_VOLTAGE=y
|
||||
# CONFIG_MEDIA_CEC_SUPPORT is not set
|
||||
@@ -226,10 +227,11 @@ CONFIG_UDMABUF=y
|
||||
CONFIG_DMABUF_SELFTESTS=m
|
||||
# CONFIG_VIRTIO_MENU is not set
|
||||
# CONFIG_VHOST_MENU is not set
|
||||
CONFIG_CLK_P100=y
|
||||
CONFIG_CLK_A210=y
|
||||
CONFIG_HWSPINLOCK=y
|
||||
CONFIG_MAILBOX=y
|
||||
CONFIG_RISCV_IOMMU=y
|
||||
CONFIG_P100_BMU=y
|
||||
CONFIG_A210_BMU=y
|
||||
CONFIG_IIO=y
|
||||
CONFIG_PWM=y
|
||||
CONFIG_PWM_THEAD=y
|
||||
@@ -155,7 +155,7 @@ CONFIG_SPI_DW_MMIO=m
|
||||
CONFIG_SPI_SPIDEV=m
|
||||
# CONFIG_PTP_1588_CLOCK is not set
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCTRL_P100=y
|
||||
CONFIG_PINCTRL_A210=y
|
||||
CONFIG_GPIOLIB=y
|
||||
CONFIG_GPIO_SYSFS=y
|
||||
CONFIG_GPIO_DWAPB=y
|
||||
@@ -203,7 +203,7 @@ CONFIG_UDMABUF=y
|
||||
CONFIG_DMABUF_SELFTESTS=m
|
||||
# CONFIG_VIRTIO_MENU is not set
|
||||
# CONFIG_VHOST_MENU is not set
|
||||
CONFIG_CLK_P100=y
|
||||
CONFIG_CLK_A210=y
|
||||
CONFIG_HWSPINLOCK=y
|
||||
CONFIG_RISCV_IOMMU=y
|
||||
CONFIG_PWM=y
|
||||
@@ -252,4 +252,4 @@ CONFIG_DETECT_HUNG_TASK=y
|
||||
CONFIG_DEBUG_ATOMIC_SLEEP=y
|
||||
# CONFIG_RCU_TRACE is not set
|
||||
# CONFIG_RUNTIME_TESTING_MENU is not set
|
||||
CONFIG_P100_BMU=y
|
||||
CONFIG_A210_BMU=y
|
||||
@@ -52,6 +52,8 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
|
||||
CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y
|
||||
CONFIG_CPUFREQ_DT=y
|
||||
CONFIG_RISCV_XUANTIE_TH1520_CPUFREQ=y
|
||||
CONFIG_VIRTUALIZATION=y
|
||||
CONFIG_KVM=y
|
||||
CONFIG_ACPI=y
|
||||
CONFIG_KPROBES=y
|
||||
# CONFIG_STRICT_KERNEL_RWX is not set
|
||||
|
||||
@@ -4,9 +4,9 @@ config ZHIHE_CLK
|
||||
bool
|
||||
def_bool ARCH_ZHIHE
|
||||
|
||||
config CLK_P100
|
||||
bool "Zhihe P100 Clock Driver"
|
||||
config CLK_A210
|
||||
bool "Zhihe A210 Clock Driver"
|
||||
depends on ARCH_ZHIHE
|
||||
default n
|
||||
help
|
||||
Build the driver for zhihe p100 Clock Driver
|
||||
Build the driver for zhihe A210 Clock Driver
|
||||
|
||||
@@ -3,4 +3,4 @@
|
||||
obj-$(CONFIG_ZHIHE_CLK) += \
|
||||
clk-helper.o
|
||||
|
||||
obj-$(CONFIG_CLK_P100) += clk-p100.o
|
||||
obj-$(CONFIG_CLK_A210) += clk-a210.o
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <dt-bindings/clock/p100-clock.h>
|
||||
#include <dt-bindings/clock/a210-clock.h>
|
||||
|
||||
#include "clk-helper.h"
|
||||
|
||||
@@ -52,7 +52,6 @@ static const char * const peri2_i2s2_src_clk_parents[] = {"audio1_pll_fout2", "a
|
||||
static const char * const peri1_qspi_ssi_clk_parents[] = {"peri1_qspi_ssi_clk_div1", "peri1_qspi_ssi_clk_div0"};
|
||||
static const char * const peri2_qspi_ssi_clk_parents[] = {"peri2_qspi_ssi_clk_div1", "peri2_qspi_ssi_clk_div0"};
|
||||
static const char * const peri1_tdm_src_clk_parents[] = {"audio1_pll_fout2", "audio0_pll_fout2"};
|
||||
static const char * const uart_sclk_parents[] = {"uart_sclk_100M", "aon_osc_clk_logic"};
|
||||
static const char * const pdm_clk_mux_parents[] = {"audio1_pll_fout2", "audio0_pll_fout2"};
|
||||
static const char * const emmc_ref_clk_mux_parents[] = {"audio0_pll_foutvco", "video_pll_foutvco"};
|
||||
static const char * const pad_sensor_vclk0_mux_parents[] = {"dpu0_pll_foutvco", "dpu1_pll_foutvco",
|
||||
@@ -223,8 +222,8 @@ static struct p100_clk_info info_top[] = {
|
||||
PLL(AUDIO1_PLL_FOUTVCO, "audio1_pll_foutvco", "osc_24m", PLL_WRAP, 0, &plls_top[AUDIO1_PLL]),
|
||||
FIXED_FACTOR(AUDIO1_PLL_FOUTPOSTDIV, "audio1_pll_foutpostdiv", "audio1_pll_foutvco", 1, 2),
|
||||
FIXED_FACTOR(AUDIO1_PLL_FOUT2, "audio1_pll_fout2", "audio1_pll_foutvco", 1, 8),
|
||||
PLL(C908_PLL_FOUTVCO, "c908_pll_foutvco", "osc_24m", PLL_WRAP, 0, &plls_top[C908_PLL]),
|
||||
PLL(C920_PLL_FOUTVCO, "c920_pll_foutvco", "osc_24m", PLL_WRAP, 0, &plls_top[C920_PLL]),
|
||||
PLL(C908_PLL_FOUTVCO, "c908_pll_foutvco", "osc_24m", CPU_SS_CPU_PLL, 0, &plls_top[C908_PLL]),
|
||||
PLL(C920_PLL_FOUTVCO, "c920_pll_foutvco", "osc_24m", CPU_SS_CPU_PLL, 0, &plls_top[C920_PLL]),
|
||||
PLL(VIDEO_PLL_FOUTVCO, "video_pll_foutvco", "top_pll_ref_clk", PLL_WRAP, 0, &plls_top[VIDEO_PLL]),
|
||||
FIXED_FACTOR(VIDEO_PLL_FOUTPOSTDIV, "video_pll_foutpostdiv", "video_pll_foutvco", 1, 2),
|
||||
FIXED_FACTOR(VIDEO_PLL_FOUT1PH0, "video_pll_fout1ph0", "video_pll_foutvco", 1, 4),
|
||||
@@ -361,9 +360,7 @@ static struct p100_clk_info info_top[] = {
|
||||
NO_DIV_EN, MUX_TYPE_DIV, 33, 63),
|
||||
MUX(TOP_PERI_TDM_SRC_CLK_MUX, "peri1_tdm_src_clk", TOP_CRG, 0x28, 25, 1,
|
||||
peri1_tdm_src_clk_parents, ARRAY_SIZE(peri1_tdm_src_clk_parents), CLK_SET_RATE_PARENT),
|
||||
FIXED_FACTOR(UART_SCLK_100M, "uart_sclk_100M", "gmac_pll_foutpostdiv", 1, 10),
|
||||
MUX(TOP_UART_SCLK_MUX, "uart_sclk", TOP_CRG, 0x28, 24, 1,
|
||||
uart_sclk_parents, ARRAY_SIZE(uart_sclk_parents), CLK_SET_RATE_PARENT),
|
||||
FIXED_FACTOR(UART_SCLK_100M, "uart_sclk", "gmac_pll_foutpostdiv", 1, 10),
|
||||
FIXED_FACTOR(PERI1_UART_SCLK, "peri1_uart_sclk", "uart_sclk", 1, 1),
|
||||
FIXED_FACTOR(PERI2_UART_SCLK, "peri2_uart_sclk", "uart_sclk", 1, 1),
|
||||
DIV(TOP_PERI_PDM_MCLK_DIV, "peri1_pdm_mclk", "pdm_clk_mux", TOP_CRG, 0x2c, 24, 8,
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <dt-bindings/clock/p100-clock.h>
|
||||
#include <dt-bindings/clock/a210-clock.h>
|
||||
|
||||
extern spinlock_t zhihe_p100_clk_lock;
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config P100_AON
|
||||
bool "P100 Aon Protocol driver"
|
||||
depends on P100_MBOX
|
||||
config A210_AON
|
||||
bool "A210 Aon Protocol driver"
|
||||
depends on A210_MBOX
|
||||
default y
|
||||
help
|
||||
ZHIHE P100 Aon is a low-level system function which runs a dedicated
|
||||
ZHIHE A210 Aon is a low-level system function which runs a dedicated
|
||||
ZHIHE riscv E902 core to provide power, clock and resource management.
|
||||
|
||||
This driver manages the IPC interface between host cpu liks thead
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_P100_AON) += p100_aon.o
|
||||
obj-$(CONFIG_A210_AON) += a210_aon.o
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/proc_fs.h>
|
||||
//#include <linux/p100_proc_debug.h>
|
||||
//#include <linux/a210_proc_debug.h>
|
||||
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#define MAX_RX_TIMEOUT (msecs_to_jiffies(3000))
|
||||
#define MAX_TX_TIMEOUT (msecs_to_jiffies(500))
|
||||
|
||||
struct p100_aon_chan {
|
||||
struct p100_aon_ipc *aon_ipc;
|
||||
struct a210_aon_chan {
|
||||
struct a210_aon_ipc *aon_ipc;
|
||||
struct mbox_client cl;
|
||||
struct mbox_chan *ch;
|
||||
struct completion tx_done;
|
||||
@@ -38,8 +38,8 @@ struct p100_aon_chan {
|
||||
struct proc_dir_entry *proc_dir;
|
||||
};
|
||||
|
||||
struct p100_aon_ipc {
|
||||
struct p100_aon_chan chans;
|
||||
struct a210_aon_ipc {
|
||||
struct a210_aon_chan chans;
|
||||
struct device *dev;
|
||||
struct mutex lock;
|
||||
struct completion done;
|
||||
@@ -50,83 +50,83 @@ struct p100_aon_ipc {
|
||||
/*
|
||||
* This type is used to indicate error response for most functions.
|
||||
*/
|
||||
enum p100_aon_error_codes {
|
||||
P100_AON_ERR_NONE = 0, /* Success */
|
||||
P100_AON_ERR_VERSION = 1, /* Incompatible API version */
|
||||
P100_AON_ERR_CONFIG = 2, /* Configuration error */
|
||||
P100_AON_ERR_PARM = 3, /* Bad parameter */
|
||||
P100_AON_ERR_NOACCESS = 4, /* Permission error (no access) */
|
||||
P100_AON_ERR_LOCKED = 5, /* Permission error (locked) */
|
||||
P100_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */
|
||||
P100_AON_ERR_NOTFOUND = 7, /* Not found */
|
||||
P100_AON_ERR_NOPOWER = 8, /* No power */
|
||||
P100_AON_ERR_IPC = 9, /* Generic IPC error */
|
||||
P100_AON_ERR_BUSY = 10, /* Resource is currently busy/active */
|
||||
P100_AON_ERR_FAIL = 11, /* General I/O failure */
|
||||
P100_AON_ERR_LAST
|
||||
enum a210_aon_error_codes {
|
||||
A210_AON_ERR_NONE = 0, /* Success */
|
||||
A210_AON_ERR_VERSION = 1, /* Incompatible API version */
|
||||
A210_AON_ERR_CONFIG = 2, /* Configuration error */
|
||||
A210_AON_ERR_PARM = 3, /* Bad parameter */
|
||||
A210_AON_ERR_NOACCESS = 4, /* Permission error (no access) */
|
||||
A210_AON_ERR_LOCKED = 5, /* Permission error (locked) */
|
||||
A210_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */
|
||||
A210_AON_ERR_NOTFOUND = 7, /* Not found */
|
||||
A210_AON_ERR_NOPOWER = 8, /* No power */
|
||||
A210_AON_ERR_IPC = 9, /* Generic IPC error */
|
||||
A210_AON_ERR_BUSY = 10, /* Resource is currently busy/active */
|
||||
A210_AON_ERR_FAIL = 11, /* General I/O failure */
|
||||
A210_AON_ERR_LAST
|
||||
};
|
||||
|
||||
static int p100_aon_linux_errmap[P100_AON_ERR_LAST] = {
|
||||
0, /* P100_AON_ERR_NONE */
|
||||
-EINVAL, /* P100_AON_ERR_VERSION */
|
||||
-EINVAL, /* P100_AON_ERR_CONFIG */
|
||||
-EINVAL, /* P100_AON_ERR_PARM */
|
||||
-EACCES, /* P100_AON_ERR_NOACCESS */
|
||||
-EACCES, /* P100_AON_ERR_LOCKED */
|
||||
-ERANGE, /* P100_AON_ERR_UNAVAILABLE */
|
||||
-EEXIST, /* P100_AON_ERR_NOTFOUND */
|
||||
-EPERM, /* P100_AON_ERR_NOPOWER */
|
||||
-EPIPE, /* P100_AON_ERR_IPC */
|
||||
-EBUSY, /* P100_AON_ERR_BUSY */
|
||||
-EIO, /* P100_AON_ERR_FAIL */
|
||||
static int a210_aon_linux_errmap[A210_AON_ERR_LAST] = {
|
||||
0, /* A210_AON_ERR_NONE */
|
||||
-EINVAL, /* A210_AON_ERR_VERSION */
|
||||
-EINVAL, /* A210_AON_ERR_CONFIG */
|
||||
-EINVAL, /* A210_AON_ERR_PARM */
|
||||
-EACCES, /* A210_AON_ERR_NOACCESS */
|
||||
-EACCES, /* A210_AON_ERR_LOCKED */
|
||||
-ERANGE, /* A210_AON_ERR_UNAVAILABLE */
|
||||
-EEXIST, /* A210_AON_ERR_NOTFOUND */
|
||||
-EPERM, /* A210_AON_ERR_NOPOWER */
|
||||
-EPIPE, /* A210_AON_ERR_IPC */
|
||||
-EBUSY, /* A210_AON_ERR_BUSY */
|
||||
-EIO, /* A210_AON_ERR_FAIL */
|
||||
};
|
||||
#define P100_AON_CHN_MAX (4)
|
||||
static struct p100_aon_ipc *p100_aon_ipc_handle[P100_AON_CHN_MAX];
|
||||
#define A210_AON_CHN_MAX (4)
|
||||
static struct a210_aon_ipc *a210_aon_ipc_handle[A210_AON_CHN_MAX];
|
||||
static uint32_t g_aon_ipc_handle_num;
|
||||
|
||||
static inline int p100_aon_to_linux_errno(int errno)
|
||||
static inline int a210_aon_to_linux_errno(int errno)
|
||||
{
|
||||
if (errno >= P100_AON_ERR_NONE && errno < P100_AON_ERR_LAST)
|
||||
return p100_aon_linux_errmap[errno];
|
||||
if (errno >= A210_AON_ERR_NONE && errno < A210_AON_ERR_LAST)
|
||||
return a210_aon_linux_errmap[errno];
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the default handle used by SCU
|
||||
*/
|
||||
int p100_aon_get_handle(struct p100_aon_ipc **ipc, char* name)
|
||||
int a210_aon_get_handle(struct a210_aon_ipc **ipc, char* name)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
if(!name)
|
||||
return -1;
|
||||
for(i = 0;i<g_aon_ipc_handle_num;i++) {
|
||||
if(!p100_aon_ipc_handle[i])
|
||||
return -1;
|
||||
if(!strcmp(name, p100_aon_ipc_handle[i]->mbox_name))) {
|
||||
*ipc = p100_aon_ipc_handle[i];
|
||||
if(!a210_aon_ipc_handle[i])
|
||||
return -EPROBE_DEFER;
|
||||
if(!strcmp(name, a210_aon_ipc_handle[i]->mbox_name)) {
|
||||
*ipc = a210_aon_ipc_handle[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
EXPORT_SYMBOL(p100_aon_get_handle);
|
||||
EXPORT_SYMBOL(a210_aon_get_handle);
|
||||
|
||||
static void p100_aon_tx_done(struct mbox_client *cl, void *mssg, int r)
|
||||
static void a210_aon_tx_done(struct mbox_client *cl, void *mssg, int r)
|
||||
{
|
||||
struct p100_aon_chan *aon_chan =
|
||||
container_of(cl, struct p100_aon_chan, cl);
|
||||
struct a210_aon_chan *aon_chan =
|
||||
container_of(cl, struct a210_aon_chan, cl);
|
||||
|
||||
complete(&aon_chan->tx_done);
|
||||
}
|
||||
|
||||
static void p100_aon_rx_callback(struct mbox_client *c, void *msg)
|
||||
static void a210_aon_rx_callback(struct mbox_client *c, void *msg)
|
||||
{
|
||||
struct p100_aon_chan *aon_chan =
|
||||
container_of(c, struct p100_aon_chan, cl);
|
||||
struct p100_aon_ipc *aon_ipc = aon_chan->aon_ipc;
|
||||
struct p100_aon_rpc_msg_hdr *hdr =
|
||||
(struct p100_aon_rpc_msg_hdr *)msg;
|
||||
uint8_t recv_size = sizeof(struct p100_aon_rpc_msg_hdr) + hdr->size;
|
||||
struct a210_aon_chan *aon_chan =
|
||||
container_of(c, struct a210_aon_chan, cl);
|
||||
struct a210_aon_ipc *aon_ipc = aon_chan->aon_ipc;
|
||||
struct a210_aon_rpc_msg_hdr *hdr =
|
||||
(struct a210_aon_rpc_msg_hdr *)msg;
|
||||
uint8_t recv_size = sizeof(struct a210_aon_rpc_msg_hdr) + hdr->size;
|
||||
|
||||
memcpy(aon_ipc->msg, msg, recv_size);
|
||||
dev_dbg(aon_ipc->dev, "msg head: 0x%x, size:%d\n", *((u32 *)msg),
|
||||
@@ -134,14 +134,14 @@ static void p100_aon_rx_callback(struct mbox_client *c, void *msg)
|
||||
complete(&aon_ipc->done);
|
||||
}
|
||||
|
||||
static int p100_aon_ipc_write(struct p100_aon_ipc *aon_ipc, void *msg)
|
||||
static int a210_aon_ipc_write(struct a210_aon_ipc *aon_ipc, void *msg)
|
||||
{
|
||||
struct p100_aon_rpc_msg_hdr *hdr = msg;
|
||||
struct p100_aon_chan *aon_chan;
|
||||
struct a210_aon_rpc_msg_hdr *hdr = msg;
|
||||
struct a210_aon_chan *aon_chan;
|
||||
u32 *data = msg;
|
||||
int ret;
|
||||
/* check size, currently it requires 7 MSG in one transfer */
|
||||
if (hdr->size != P100_AON_RPC_MSG_NUM)
|
||||
if (hdr->size != A210_AON_RPC_MSG_NUM)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(aon_ipc->dev, "RPC SVC %u FUNC %u SIZE %u\n", hdr->svc,
|
||||
@@ -164,10 +164,10 @@ static int p100_aon_ipc_write(struct p100_aon_ipc *aon_ipc, void *msg)
|
||||
/*
|
||||
* RPC command/response
|
||||
*/
|
||||
int p100_aon_call_rpc(struct p100_aon_ipc *aon_ipc, void *msg,
|
||||
int a210_aon_call_rpc(struct a210_aon_ipc *aon_ipc, void *msg,
|
||||
void *ack_msg, bool have_resp)
|
||||
{
|
||||
struct p100_aon_rpc_msg_hdr *hdr = msg;
|
||||
struct a210_aon_rpc_msg_hdr *hdr = msg;
|
||||
int ret = 0;
|
||||
if (WARN_ON(!aon_ipc || !msg))
|
||||
return -EINVAL;
|
||||
@@ -175,7 +175,7 @@ int p100_aon_call_rpc(struct p100_aon_ipc *aon_ipc, void *msg,
|
||||
return -EINVAL;
|
||||
mutex_lock(&aon_ipc->lock);
|
||||
reinit_completion(&aon_ipc->done);
|
||||
RPC_SET_VER(hdr, P100_AON_RPC_VERSION);
|
||||
RPC_SET_VER(hdr, A210_AON_RPC_VERSION);
|
||||
/*svc id use 6bit for version 2*/
|
||||
RPC_SET_SVC_ID(hdr, hdr->svc);
|
||||
RPC_SET_SVC_FLAG_MSG_TYPE(hdr, RPC_SVC_MSG_TYPE_DATA);
|
||||
@@ -185,7 +185,7 @@ int p100_aon_call_rpc(struct p100_aon_ipc *aon_ipc, void *msg,
|
||||
} else {
|
||||
RPC_SET_SVC_FLAG_ACK_TYPE(hdr, RPC_SVC_MSG_NO_NEED_ACK);
|
||||
}
|
||||
ret = p100_aon_ipc_write(aon_ipc, msg);
|
||||
ret = a210_aon_ipc_write(aon_ipc, msg);
|
||||
if (ret < 0) {
|
||||
dev_err(aon_ipc->dev, "RPC send msg failed: %d\n", ret);
|
||||
goto out;
|
||||
@@ -199,7 +199,7 @@ int p100_aon_call_rpc(struct p100_aon_ipc *aon_ipc, void *msg,
|
||||
}
|
||||
|
||||
/* response status is stored in msg data[0] field */
|
||||
struct p100_aon_rpc_ack_common *ack = ack_msg;
|
||||
struct a210_aon_rpc_ack_common *ack = ack_msg;
|
||||
ret = ack->err_code;
|
||||
}
|
||||
out:
|
||||
@@ -207,15 +207,15 @@ out:
|
||||
|
||||
dev_dbg(aon_ipc->dev, "RPC SVC done\n");
|
||||
|
||||
return p100_aon_to_linux_errno(ret);
|
||||
return a210_aon_to_linux_errno(ret);
|
||||
}
|
||||
EXPORT_SYMBOL(p100_aon_call_rpc);
|
||||
EXPORT_SYMBOL(a210_aon_call_rpc);
|
||||
|
||||
static int p100_aon_probe(struct platform_device *pdev)
|
||||
static int a210_aon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct p100_aon_ipc *aon_ipc;
|
||||
struct p100_aon_chan *aon_chan;
|
||||
struct a210_aon_ipc *aon_ipc;
|
||||
struct a210_aon_chan *aon_chan;
|
||||
struct mbox_client *cl;
|
||||
struct device_node *np;
|
||||
int ret;
|
||||
@@ -227,10 +227,10 @@ static int p100_aon_probe(struct platform_device *pdev)
|
||||
cl->dev = dev;
|
||||
cl->tx_block = false;
|
||||
cl->knows_txdone = true;
|
||||
cl->rx_callback = p100_aon_rx_callback;
|
||||
cl->rx_callback = a210_aon_rx_callback;
|
||||
|
||||
/* Initial tx_done completion as "done" */
|
||||
cl->tx_done = p100_aon_tx_done;
|
||||
cl->tx_done = a210_aon_tx_done;
|
||||
init_completion(&aon_chan->tx_done);
|
||||
complete(&aon_chan->tx_done);
|
||||
|
||||
@@ -251,45 +251,45 @@ static int p100_aon_probe(struct platform_device *pdev)
|
||||
mutex_init(&aon_ipc->lock);
|
||||
init_completion(&aon_ipc->done);
|
||||
aon_chan->log_ctrl = NULL;
|
||||
if(g_aon_ipc_handle_num>=P100_AON_CHN_MAX) {
|
||||
if(g_aon_ipc_handle_num>=A210_AON_CHN_MAX) {
|
||||
dev_err(dev, "aon_ipc:%s handle num overflow\n",aon_ipc->mbox_name);
|
||||
return -1;
|
||||
}
|
||||
p100_aon_ipc_handle[g_aon_ipc_handle_num] = aon_ipc;
|
||||
a210_aon_ipc_handle[g_aon_ipc_handle_num] = aon_ipc;
|
||||
g_aon_ipc_handle_num++;
|
||||
return devm_of_platform_populate(dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id p100_aon_match[] = {
|
||||
static const struct of_device_id a210_aon_match[] = {
|
||||
{
|
||||
.compatible = "zhihe,p100-aon",
|
||||
.compatible = "zhihe,a210-aon",
|
||||
},
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
|
||||
static int __maybe_unused p100_aon_resume_noirq(struct device *dev)
|
||||
static int __maybe_unused a210_aon_resume_noirq(struct device *dev)
|
||||
{
|
||||
#if 0
|
||||
struct p100_aon_chan *aon_chan;
|
||||
aon_chan = &p100_aon_ipc_handle->chans;
|
||||
struct a210_aon_chan *aon_chan;
|
||||
aon_chan = &a210_aon_ipc_handle->chans;
|
||||
|
||||
complete(&aon_chan->tx_done);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops p100_aon_pm_ops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, p100_aon_resume_noirq)
|
||||
static const struct dev_pm_ops a210_aon_pm_ops = {
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, a210_aon_resume_noirq)
|
||||
};
|
||||
static struct platform_driver p100_aon_driver = {
|
||||
static struct platform_driver a210_aon_driver = {
|
||||
.driver = {
|
||||
.name = "p100-aon",
|
||||
.of_match_table = p100_aon_match,
|
||||
.pm = &p100_aon_pm_ops,
|
||||
.name = "a210-aon",
|
||||
.of_match_table = a210_aon_match,
|
||||
.pm = &a210_aon_pm_ops,
|
||||
},
|
||||
.probe = p100_aon_probe,
|
||||
.probe = a210_aon_probe,
|
||||
};
|
||||
builtin_platform_driver(p100_aon_driver);
|
||||
builtin_platform_driver(a210_aon_driver);
|
||||
|
||||
MODULE_AUTHOR("xionglue.huang <huangxionglue@zhcomputing.com>");
|
||||
MODULE_DESCRIPTION("ZHIHE firmware protocol driver");
|
||||
@@ -11,7 +11,7 @@ config ZH_IOPMP
|
||||
depends on ARCH_ZHIHE || COMPILE_TEST
|
||||
help
|
||||
Say Y here to include support for zhihe iopmp found on found on
|
||||
P100 fullmask devices
|
||||
A210 fullmask devices
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called zh-iopmp.
|
||||
|
||||
|
||||
@@ -303,12 +303,12 @@ config TH1520_MBOX
|
||||
Mailbox implementation for Xuantie TH1520 SoCs.
|
||||
Say Y here if you want to have this support. If unsure say N.
|
||||
|
||||
config P100_MBOX
|
||||
tristate "p100 Mailbox driver"
|
||||
config A210_MBOX
|
||||
tristate "A210 Mailbox driver"
|
||||
depends on ARCH_ZHIHE || COMPILE_TEST
|
||||
default y
|
||||
help
|
||||
Mailbox implementation for ZHIHE p100 SoCs.
|
||||
Mailbox implementation for ZHIHE A210 SoCs.
|
||||
Say Y here if you want to have this support. If unsure say N.
|
||||
|
||||
endif
|
||||
|
||||
@@ -65,4 +65,4 @@ obj-$(CONFIG_APPLE_MAILBOX) += apple-mailbox.o
|
||||
|
||||
obj-$(CONFIG_TH1520_MBOX) += th1520-mailbox.o
|
||||
|
||||
obj-$(CONFIG_P100_MBOX) += p100-mailbox.o
|
||||
obj-$(CONFIG_A210_MBOX) += a210-mailbox.o
|
||||
|
||||
576
drivers/mailbox/a210-mailbox.c
Normal file
576
drivers/mailbox/a210-mailbox.c
Normal file
@@ -0,0 +1,576 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* a210 MailBox support
|
||||
*
|
||||
* Copyright (C) 2024 ZHIHE Group Holding Limited.
|
||||
*
|
||||
* Author: xionglue.huang <huangxionglue@zhcomputing.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mailbox_controller.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Status Register */
|
||||
#define A210_MBOX_STA 0x0
|
||||
#define A210_MBOX_CLR 0x4
|
||||
#define A210_MBOX_MASK 0xc
|
||||
|
||||
/* Transmit/receive data register:
|
||||
* INFO0 ~ INFO6
|
||||
*/
|
||||
#define A210_MBOX_INFO_NUM 8
|
||||
#define A210_MBOX_DATA_INFO_NUM 7
|
||||
#define A210_MBOX_INFO0 0x14
|
||||
/* Transmit ack register: INFO7 */
|
||||
#define A210_MBOX_INFO7 0x30
|
||||
|
||||
/* Generate remote icu IRQ Register */
|
||||
#define A210_MBOX_GEN 0x10
|
||||
#define A210_MBOX_GEN_RX_DATA BIT(6)
|
||||
#define A210_MBOX_GEN_TX_ACK BIT(7)
|
||||
|
||||
#define A210_MBOX_CHAN_RES_SIZE 0x1000
|
||||
#define A210_MBOX_CHANS 4
|
||||
#define A210_MBOX_CHAN_NAME_SIZE 20
|
||||
|
||||
#define A210_MBOX_ACK_MAGIC 0xdeadbeaf
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/* store MBOX context across system-wide suspend/resume transitions */
|
||||
struct a210_mbox_context {
|
||||
u32 intr_mask[A210_MBOX_CHANS - 1];
|
||||
};
|
||||
|
||||
#endif
|
||||
enum a210_mbox_chan_type {
|
||||
A210_MBOX_TYPE_TXRX, /* Tx & Rx chan */
|
||||
A210_MBOX_TYPE_DB, /* Tx & Rx doorbell */
|
||||
};
|
||||
enum a210_mbox_icu_cpu_id {
|
||||
A210_MBOX_ICU_CPU0 = 0, /*die0-908*/
|
||||
A210_MBOX_ICU_CPU1 = 1,
|
||||
A210_MBOX_ICU_CPU2 = 2,
|
||||
A210_MBOX_ICU_CPU3 = 3,
|
||||
};
|
||||
|
||||
enum a210_mbox_local_id {
|
||||
A210_MBOX_INTERRUPT = 0,
|
||||
A210_MBOX_DATA_CH0 = 1, /* die0-908--die0-902*/
|
||||
A210_MBOX_DATA_CH1 = 2,
|
||||
A210_MBOX_DATA_CH2 = 3,
|
||||
};
|
||||
enum a210_mbox_remote_id {
|
||||
A210_MBOX_REMOTE_CH0 = 0, /* die0-908--die0-902*/
|
||||
A210_MBOX_REMOTE_CH1 = 1,
|
||||
A210_MBOX_REMOTE_CH2 = 2,
|
||||
};
|
||||
|
||||
struct a210_mbox_con_priv {
|
||||
enum a210_mbox_local_id idx;
|
||||
enum a210_mbox_chan_type type;
|
||||
void __iomem *comm_local_base;
|
||||
void __iomem *comm_remote_base;
|
||||
char irq_desc[A210_MBOX_CHAN_NAME_SIZE];
|
||||
struct mbox_chan *chan;
|
||||
struct tasklet_struct txdb_tasklet;
|
||||
};
|
||||
|
||||
struct a210_mbox_priv {
|
||||
struct device *dev;
|
||||
void __iomem *local_icu[A210_MBOX_CHANS];
|
||||
void __iomem *remote_icu[A210_MBOX_CHANS - 1];
|
||||
void __iomem *cur_cpu_ch_base;
|
||||
enum a210_mbox_icu_cpu_id cur_icu_cpu_id;
|
||||
spinlock_t mbox_lock; /* control register lock */
|
||||
|
||||
struct mbox_controller mbox;
|
||||
struct mbox_chan mbox_chans[A210_MBOX_CHANS];
|
||||
|
||||
struct a210_mbox_con_priv con_priv[A210_MBOX_CHANS];
|
||||
struct clk *clk;
|
||||
int irq;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct a210_mbox_context *ctx;
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct a210_mbox_priv *to_a210_mbox_priv(struct mbox_controller *mbox)
|
||||
{
|
||||
return container_of(mbox, struct a210_mbox_priv, mbox);
|
||||
}
|
||||
|
||||
static void a210_mbox_write(struct a210_mbox_priv *priv, u32 val, u32 offs)
|
||||
{
|
||||
iowrite32(val, priv->cur_cpu_ch_base + offs);
|
||||
}
|
||||
|
||||
static u32 a210_mbox_read(struct a210_mbox_priv *priv, u32 offs)
|
||||
{
|
||||
return ioread32(priv->cur_cpu_ch_base + offs);
|
||||
}
|
||||
|
||||
static u32 a210_mbox_rmw(struct a210_mbox_priv *priv,
|
||||
u32 off, u32 set, u32 clr)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->mbox_lock, flags);
|
||||
val = a210_mbox_read(priv, off);
|
||||
val &= ~clr;
|
||||
val |= set;
|
||||
a210_mbox_write(priv, val, off);
|
||||
spin_unlock_irqrestore(&priv->mbox_lock, flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void a210_mbox_chan_write(struct a210_mbox_con_priv *cp,
|
||||
u32 val, u32 offs, bool is_remote)
|
||||
{
|
||||
if (is_remote)
|
||||
iowrite32(val, cp->comm_remote_base + offs);
|
||||
else
|
||||
iowrite32(val, cp->comm_local_base + offs);
|
||||
}
|
||||
|
||||
static u32 a210_mbox_chan_read(struct a210_mbox_con_priv *cp,
|
||||
u32 offs, bool is_remote)
|
||||
{
|
||||
uint32_t t = 0;
|
||||
if (is_remote)
|
||||
t = ioread32(cp->comm_remote_base + offs);
|
||||
else
|
||||
t = ioread32(cp->comm_local_base + offs);
|
||||
return t;
|
||||
}
|
||||
|
||||
static void a210_mbox_chan_rmw(struct a210_mbox_con_priv *cp,
|
||||
u32 off, u32 set, u32 clr, bool is_remote)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
struct a210_mbox_priv *priv = to_a210_mbox_priv(cp->chan->mbox);
|
||||
spin_lock_irqsave(&priv->mbox_lock, flags);
|
||||
val = a210_mbox_chan_read(cp, off, is_remote);
|
||||
val &= ~clr;
|
||||
val |= set;
|
||||
a210_mbox_chan_write(cp, val, off, is_remote);
|
||||
spin_unlock_irqrestore(&priv->mbox_lock, flags);
|
||||
}
|
||||
|
||||
static void a210_mbox_chan_rd_data(struct a210_mbox_con_priv *cp,
|
||||
void *data, bool is_remote)
|
||||
{
|
||||
u32 i;
|
||||
u32 *arg = data;
|
||||
u32 off = A210_MBOX_INFO0;
|
||||
|
||||
/* read info0 ~ info6, totally 28 bytes
|
||||
* requires data memory size is 28 bytes
|
||||
*/
|
||||
for (i = 0; i < A210_MBOX_DATA_INFO_NUM; i++) {
|
||||
*arg = a210_mbox_chan_read(cp, off, is_remote);
|
||||
off += 4;
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
|
||||
static void a210_mbox_chan_wr_data(struct a210_mbox_con_priv *cp,
|
||||
void *data, bool is_remote)
|
||||
{
|
||||
u32 i;
|
||||
u32 *arg = data;
|
||||
u32 off = A210_MBOX_INFO0;
|
||||
|
||||
/* write info0 ~ info6, totally 28 bytes
|
||||
* requires data memory is 28 bytes valid data
|
||||
*/
|
||||
for (i = 0; i < A210_MBOX_DATA_INFO_NUM; i++) {
|
||||
a210_mbox_chan_write(cp, *arg, off, is_remote);
|
||||
off += 4;
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
|
||||
static void a210_mbox_chan_wr_ack(struct a210_mbox_con_priv *cp,
|
||||
void *data, bool is_remote)
|
||||
{
|
||||
u32 *arg = data;
|
||||
u32 off = A210_MBOX_INFO7;
|
||||
|
||||
a210_mbox_chan_write(cp, *arg, off, is_remote);
|
||||
}
|
||||
|
||||
static int a210_mbox_chan_id_to_mapbit(struct a210_mbox_con_priv *cp)
|
||||
{
|
||||
int i;
|
||||
int mapbit = 0;
|
||||
for (i = 0; i < A210_MBOX_CHANS; i++) {
|
||||
if (i == cp->idx)
|
||||
return mapbit;
|
||||
|
||||
if (i != A210_MBOX_INTERRUPT)
|
||||
mapbit++;
|
||||
}
|
||||
|
||||
if (i == A210_MBOX_CHANS)
|
||||
dev_err(cp->chan->mbox->dev, "convert to mapbit failed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void a210_mbox_txdb_tasklet(unsigned long data)
|
||||
{
|
||||
struct a210_mbox_con_priv *cp = (struct a210_mbox_con_priv *)data;
|
||||
|
||||
mbox_chan_txdone(cp->chan, 0);
|
||||
}
|
||||
|
||||
static irqreturn_t a210_mbox_isr(int irq, void *p)
|
||||
{
|
||||
u32 info0_data, info7_data;
|
||||
u32 sta, dat[A210_MBOX_DATA_INFO_NUM];
|
||||
u32 ack_magic = A210_MBOX_ACK_MAGIC;
|
||||
struct mbox_chan *chan = p;
|
||||
struct a210_mbox_con_priv *cp = chan->con_priv;
|
||||
int mapbit = a210_mbox_chan_id_to_mapbit(cp);
|
||||
struct a210_mbox_priv *priv = to_a210_mbox_priv(chan->mbox);
|
||||
|
||||
sta = a210_mbox_read(priv, A210_MBOX_STA);
|
||||
if (!(sta & BIT(mapbit)))
|
||||
return IRQ_NONE;
|
||||
/* clear chan irq bit in STA register */
|
||||
a210_mbox_rmw(priv, A210_MBOX_CLR, BIT(mapbit), 0);
|
||||
/* rx doorbell */
|
||||
if (cp->type == A210_MBOX_TYPE_DB) {
|
||||
mbox_chan_received_data(cp->chan, NULL);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
/* info0 is the protocol word, should not be zero! */
|
||||
info0_data = a210_mbox_chan_read(cp, A210_MBOX_INFO0, false);
|
||||
if (info0_data) {
|
||||
/* read info0~info6 data */
|
||||
a210_mbox_chan_rd_data(cp, dat, false);
|
||||
|
||||
/* clear local info0 */
|
||||
a210_mbox_chan_write(cp, 0x0, A210_MBOX_INFO0, false);
|
||||
/* notify remote cpu */
|
||||
a210_mbox_chan_wr_ack(cp, &ack_magic, true);
|
||||
/* transfer the data to client */
|
||||
mbox_chan_received_data(chan, (void *)dat);
|
||||
}
|
||||
/* info7 magic value mean the real ack signal, not generate bit7 */
|
||||
info7_data = a210_mbox_chan_read(cp, A210_MBOX_INFO7, false);
|
||||
if (info7_data == A210_MBOX_ACK_MAGIC) {
|
||||
/* clear local info7 */
|
||||
a210_mbox_chan_write(cp, 0x0, A210_MBOX_INFO7, false);
|
||||
|
||||
/* notify framework the last TX has completed */
|
||||
mbox_chan_txdone(chan, 0);
|
||||
}
|
||||
if (!info0_data && !info7_data)
|
||||
return IRQ_NONE;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int a210_mbox_send_data(struct mbox_chan *chan, void *data)
|
||||
{
|
||||
struct a210_mbox_con_priv *cp = chan->con_priv;
|
||||
if (cp->type == A210_MBOX_TYPE_DB)
|
||||
tasklet_schedule(&cp->txdb_tasklet);
|
||||
else
|
||||
a210_mbox_chan_wr_data(cp, data, true);
|
||||
a210_mbox_chan_rmw(cp, A210_MBOX_GEN, A210_MBOX_GEN_RX_DATA, 0,
|
||||
true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a210_mbox_startup(struct mbox_chan *chan)
|
||||
{
|
||||
int ret;
|
||||
int mask_bit;
|
||||
u32 data[8] = {0};
|
||||
struct a210_mbox_con_priv *cp = chan->con_priv;
|
||||
struct a210_mbox_priv *priv = to_a210_mbox_priv(chan->mbox);
|
||||
/* clear local and remote generate and info0~info7 */
|
||||
a210_mbox_chan_rmw(cp, A210_MBOX_GEN, 0x0, 0xff, true);
|
||||
a210_mbox_chan_rmw(cp, A210_MBOX_GEN, 0x0, 0xff, false);
|
||||
a210_mbox_chan_wr_ack(cp, &data[7], true);
|
||||
a210_mbox_chan_wr_ack(cp, &data[7], false);
|
||||
a210_mbox_chan_wr_data(cp, &data[0], true);
|
||||
a210_mbox_chan_wr_data(cp, &data[0], false);
|
||||
/* enable the chan mask */
|
||||
mask_bit = a210_mbox_chan_id_to_mapbit(cp);
|
||||
a210_mbox_rmw(priv, A210_MBOX_MASK, BIT(mask_bit), 0);
|
||||
|
||||
if (cp->type == A210_MBOX_TYPE_DB)
|
||||
/* tx doorbell doesn't have ACK, rx doorbell requires isr */
|
||||
tasklet_init(&cp->txdb_tasklet, a210_mbox_txdb_tasklet,
|
||||
(unsigned long)cp);
|
||||
ret = request_irq(priv->irq, a210_mbox_isr, IRQF_SHARED |
|
||||
IRQF_NO_SUSPEND, cp->irq_desc, chan);
|
||||
if (ret) {
|
||||
dev_err(priv->dev,
|
||||
"Unable to acquire IRQ %d\n", priv->irq);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void a210_mbox_shutdown(struct mbox_chan *chan)
|
||||
{
|
||||
int mask_bit;
|
||||
struct a210_mbox_con_priv *cp = chan->con_priv;
|
||||
struct a210_mbox_priv *priv = to_a210_mbox_priv(chan->mbox);
|
||||
|
||||
/* clear the chan mask */
|
||||
mask_bit = a210_mbox_chan_id_to_mapbit(cp);
|
||||
a210_mbox_rmw(priv, A210_MBOX_MASK, 0, BIT(mask_bit));
|
||||
|
||||
free_irq(priv->irq, chan);
|
||||
}
|
||||
|
||||
static const struct mbox_chan_ops a210_mbox_ops = {
|
||||
.send_data = a210_mbox_send_data,
|
||||
.startup = a210_mbox_startup,
|
||||
.shutdown = a210_mbox_shutdown,
|
||||
};
|
||||
|
||||
static int a210_mbox_init_generic(struct a210_mbox_priv *priv)
|
||||
{
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
priv->ctx = devm_kzalloc(priv->dev, sizeof(*priv->ctx), GFP_KERNEL);
|
||||
if (!priv->ctx)
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
/* Set default configuration */
|
||||
a210_mbox_write(priv, 0xff, A210_MBOX_CLR);
|
||||
a210_mbox_write(priv, 0x0, A210_MBOX_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mbox_chan *a210_mbox_xlate(struct mbox_controller *mbox,
|
||||
const struct of_phandle_args *sp)
|
||||
{
|
||||
u32 chan, type;
|
||||
struct a210_mbox_con_priv *cp;
|
||||
|
||||
if (sp->args_count != 2) {
|
||||
dev_err(mbox->dev,
|
||||
"Invalid argument count %d\n", sp->args_count);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
chan = sp->args[0]; /* comm remote channel */
|
||||
type = sp->args[1]; /* comm channel type */
|
||||
if (chan >= mbox->num_chans) {
|
||||
dev_err(mbox->dev, "Not supported channel number: %d\n", chan);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (type > A210_MBOX_TYPE_DB) {
|
||||
dev_err(mbox->dev,
|
||||
"Not supported the type for channel[%d]\n", chan);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
cp = mbox->chans[chan].con_priv;
|
||||
cp->type = type;
|
||||
|
||||
return &mbox->chans[chan];
|
||||
}
|
||||
|
||||
static int a210_mbox_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
unsigned int i;
|
||||
struct resource *res;
|
||||
struct a210_mbox_priv *priv;
|
||||
unsigned int remote_idx = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_property_read_u32(np, "icu_cpu_id", &priv->cur_icu_cpu_id)) {
|
||||
dev_err(dev, "icu_cpu_id is missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
priv->dev = dev;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "interrupt_addr");
|
||||
priv->local_icu[A210_MBOX_INTERRUPT] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->local_icu[A210_MBOX_INTERRUPT]))
|
||||
return PTR_ERR(priv->local_icu[A210_MBOX_INTERRUPT]);
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "local_addr0");
|
||||
priv->local_icu[A210_MBOX_DATA_CH0] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->local_icu[A210_MBOX_DATA_CH0]))
|
||||
return PTR_ERR(priv->local_icu[A210_MBOX_DATA_CH0]);
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu0");
|
||||
priv->remote_icu[A210_MBOX_REMOTE_CH0] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->remote_icu[A210_MBOX_REMOTE_CH0]))
|
||||
return PTR_ERR(priv->remote_icu[A210_MBOX_REMOTE_CH0]);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "local_addr1");
|
||||
if(res!=NULL) {
|
||||
priv->local_icu[A210_MBOX_DATA_CH1] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->local_icu[A210_MBOX_DATA_CH1]))
|
||||
return PTR_ERR(priv->local_icu[A210_MBOX_DATA_CH1]);
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu1");
|
||||
if(res!=NULL) {
|
||||
priv->remote_icu[A210_MBOX_REMOTE_CH1] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->remote_icu[A210_MBOX_REMOTE_CH1]))
|
||||
return PTR_ERR(priv->remote_icu[A210_MBOX_REMOTE_CH1]);
|
||||
}
|
||||
|
||||
priv->cur_cpu_ch_base = priv->local_icu[A210_MBOX_INTERRUPT];
|
||||
priv->irq = platform_get_irq(pdev, 0);
|
||||
if (priv->irq < 0)
|
||||
return priv->irq;
|
||||
priv->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(priv->clk)) {
|
||||
if (PTR_ERR(priv->clk) != -ENOENT)
|
||||
return PTR_ERR(priv->clk);
|
||||
priv->clk = NULL;
|
||||
}
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
/* init the chans */
|
||||
for (i = 0; i < A210_MBOX_CHANS; i++) {
|
||||
struct a210_mbox_con_priv *cp = &priv->con_priv[i];
|
||||
cp->idx = i;
|
||||
cp->chan = &priv->mbox_chans[i];
|
||||
priv->mbox_chans[i].con_priv = cp;
|
||||
snprintf(cp->irq_desc, sizeof(cp->irq_desc),
|
||||
"a210_mbox_chan[%i]", cp->idx);
|
||||
cp->comm_local_base = priv->local_icu[i];
|
||||
if (i != A210_MBOX_INTERRUPT) {
|
||||
cp->comm_remote_base = priv->remote_icu[remote_idx];
|
||||
remote_idx++;
|
||||
}
|
||||
}
|
||||
spin_lock_init(&priv->mbox_lock);
|
||||
|
||||
priv->mbox.dev = dev;
|
||||
priv->mbox.ops = &a210_mbox_ops;
|
||||
priv->mbox.chans = priv->mbox_chans;
|
||||
priv->mbox.num_chans = A210_MBOX_CHANS;
|
||||
priv->mbox.of_xlate = a210_mbox_xlate;
|
||||
priv->mbox.txdone_irq = true;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
ret = a210_mbox_init_generic(priv);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to init mailbox context\n");
|
||||
return ret;
|
||||
}
|
||||
return devm_mbox_controller_register(dev, &priv->mbox);
|
||||
}
|
||||
|
||||
static int a210_mbox_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct a210_mbox_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id a210_mbox_dt_ids[] = {
|
||||
{ .compatible = "zhihe,a210-mbox" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, a210_mbox_dt_ids);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int __maybe_unused a210_mbox_suspend_noirq(struct device *dev)
|
||||
{
|
||||
u32 i;
|
||||
struct a210_mbox_priv *priv = dev_get_drvdata(dev);
|
||||
struct a210_mbox_context *ctx = priv->ctx;
|
||||
|
||||
/*
|
||||
* ONLY interrupt mask bit should be stored and restores.
|
||||
* INFO data all assumed to be lost.
|
||||
*/
|
||||
for (i = 0 ; i < A210_MBOX_CHANS; i++)
|
||||
ctx->intr_mask[i] = ioread32(priv->local_icu[i] +
|
||||
A210_MBOX_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused a210_mbox_resume_noirq(struct device *dev)
|
||||
{
|
||||
u32 i;
|
||||
struct a210_mbox_priv *priv = dev_get_drvdata(dev);
|
||||
struct a210_mbox_context *ctx = priv->ctx;
|
||||
|
||||
for (i = 0 ; i < A210_MBOX_CHANS; i++)
|
||||
iowrite32(ctx->intr_mask[i],
|
||||
priv->local_icu[i] + A210_MBOX_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int __maybe_unused a210_mbox_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct a210_mbox_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused a210_mbox_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct a210_mbox_priv *priv = dev_get_drvdata(dev);
|
||||
int ret = clk_prepare_enable(priv->clk);
|
||||
|
||||
if (ret)
|
||||
dev_err(dev, "failed to enable clock\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops a210_mbox_pm_ops = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(a210_mbox_suspend_noirq,
|
||||
a210_mbox_resume_noirq)
|
||||
#endif
|
||||
SET_RUNTIME_PM_OPS(a210_mbox_runtime_suspend,
|
||||
a210_mbox_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver a210_mbox_driver = {
|
||||
.probe = a210_mbox_probe,
|
||||
.remove = a210_mbox_remove,
|
||||
.driver = {
|
||||
.name = "a210_mbox",
|
||||
.of_match_table = a210_mbox_dt_ids,
|
||||
.pm = &a210_mbox_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(a210_mbox_driver);
|
||||
|
||||
MODULE_AUTHOR("xionglue.huang <huangxionglue@zhcomputing.com>");
|
||||
MODULE_DESCRIPTION("a210 Mailbox IPC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -1,576 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* p100 MailBox support
|
||||
*
|
||||
* Copyright (C) 2024 ZHIHE Group Holding Limited.
|
||||
*
|
||||
* Author: xionglue.huang <huangxionglue@zhcomputing.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mailbox_controller.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* Status Register */
|
||||
#define P100_MBOX_STA 0x0
|
||||
#define P100_MBOX_CLR 0x4
|
||||
#define P100_MBOX_MASK 0xc
|
||||
|
||||
/* Transmit/receive data register:
|
||||
* INFO0 ~ INFO6
|
||||
*/
|
||||
#define P100_MBOX_INFO_NUM 8
|
||||
#define P100_MBOX_DATA_INFO_NUM 7
|
||||
#define P100_MBOX_INFO0 0x14
|
||||
/* Transmit ack register: INFO7 */
|
||||
#define P100_MBOX_INFO7 0x30
|
||||
|
||||
/* Generate remote icu IRQ Register */
|
||||
#define P100_MBOX_GEN 0x10
|
||||
#define P100_MBOX_GEN_RX_DATA BIT(6)
|
||||
#define P100_MBOX_GEN_TX_ACK BIT(7)
|
||||
|
||||
#define P100_MBOX_CHAN_RES_SIZE 0x1000
|
||||
#define P100_MBOX_CHANS 4
|
||||
#define P100_MBOX_CHAN_NAME_SIZE 20
|
||||
|
||||
#define P100_MBOX_ACK_MAGIC 0xdeadbeaf
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
/* store MBOX context across system-wide suspend/resume transitions */
|
||||
struct p100_mbox_context {
|
||||
u32 intr_mask[P100_MBOX_CHANS - 1];
|
||||
};
|
||||
|
||||
#endif
|
||||
enum p100_mbox_chan_type {
|
||||
P100_MBOX_TYPE_TXRX, /* Tx & Rx chan */
|
||||
P100_MBOX_TYPE_DB, /* Tx & Rx doorbell */
|
||||
};
|
||||
enum p100_mbox_icu_cpu_id {
|
||||
P100_MBOX_ICU_CPU0 = 0, /*die0-908*/
|
||||
P100_MBOX_ICU_CPU1 = 1,
|
||||
P100_MBOX_ICU_CPU2 = 2,
|
||||
P100_MBOX_ICU_CPU3 = 3,
|
||||
};
|
||||
|
||||
enum p100_mbox_local_id {
|
||||
P100_MBOX_INTERRUPT = 0,
|
||||
P100_MBOX_DATA_CH0 = 1, /* die0-908--die0-902*/
|
||||
P100_MBOX_DATA_CH1 = 2,
|
||||
P100_MBOX_DATA_CH2 = 3,
|
||||
};
|
||||
enum p100_mbox_remote_id {
|
||||
P100_MBOX_REMOTE_CH0 = 0, /* die0-908--die0-902*/
|
||||
P100_MBOX_REMOTE_CH1 = 1,
|
||||
P100_MBOX_REMOTE_CH2 = 2,
|
||||
};
|
||||
|
||||
struct p100_mbox_con_priv {
|
||||
enum p100_mbox_local_id idx;
|
||||
enum p100_mbox_chan_type type;
|
||||
void __iomem *comm_local_base;
|
||||
void __iomem *comm_remote_base;
|
||||
char irq_desc[P100_MBOX_CHAN_NAME_SIZE];
|
||||
struct mbox_chan *chan;
|
||||
struct tasklet_struct txdb_tasklet;
|
||||
};
|
||||
|
||||
struct p100_mbox_priv {
|
||||
struct device *dev;
|
||||
void __iomem *local_icu[P100_MBOX_CHANS];
|
||||
void __iomem *remote_icu[P100_MBOX_CHANS - 1];
|
||||
void __iomem *cur_cpu_ch_base;
|
||||
enum p100_mbox_icu_cpu_id cur_icu_cpu_id;
|
||||
spinlock_t mbox_lock; /* control register lock */
|
||||
|
||||
struct mbox_controller mbox;
|
||||
struct mbox_chan mbox_chans[P100_MBOX_CHANS];
|
||||
|
||||
struct p100_mbox_con_priv con_priv[P100_MBOX_CHANS];
|
||||
struct clk *clk;
|
||||
int irq;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct p100_mbox_context *ctx;
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct p100_mbox_priv *to_p100_mbox_priv(struct mbox_controller *mbox)
|
||||
{
|
||||
return container_of(mbox, struct p100_mbox_priv, mbox);
|
||||
}
|
||||
|
||||
static void p100_mbox_write(struct p100_mbox_priv *priv, u32 val, u32 offs)
|
||||
{
|
||||
iowrite32(val, priv->cur_cpu_ch_base + offs);
|
||||
}
|
||||
|
||||
static u32 p100_mbox_read(struct p100_mbox_priv *priv, u32 offs)
|
||||
{
|
||||
return ioread32(priv->cur_cpu_ch_base + offs);
|
||||
}
|
||||
|
||||
static u32 p100_mbox_rmw(struct p100_mbox_priv *priv,
|
||||
u32 off, u32 set, u32 clr)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->mbox_lock, flags);
|
||||
val = p100_mbox_read(priv, off);
|
||||
val &= ~clr;
|
||||
val |= set;
|
||||
p100_mbox_write(priv, val, off);
|
||||
spin_unlock_irqrestore(&priv->mbox_lock, flags);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void p100_mbox_chan_write(struct p100_mbox_con_priv *cp,
|
||||
u32 val, u32 offs, bool is_remote)
|
||||
{
|
||||
if (is_remote)
|
||||
iowrite32(val, cp->comm_remote_base + offs);
|
||||
else
|
||||
iowrite32(val, cp->comm_local_base + offs);
|
||||
}
|
||||
|
||||
static u32 p100_mbox_chan_read(struct p100_mbox_con_priv *cp,
|
||||
u32 offs, bool is_remote)
|
||||
{
|
||||
uint32_t t = 0;
|
||||
if (is_remote)
|
||||
t = ioread32(cp->comm_remote_base + offs);
|
||||
else
|
||||
t = ioread32(cp->comm_local_base + offs);
|
||||
return t;
|
||||
}
|
||||
|
||||
static void p100_mbox_chan_rmw(struct p100_mbox_con_priv *cp,
|
||||
u32 off, u32 set, u32 clr, bool is_remote)
|
||||
{
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
struct p100_mbox_priv *priv = to_p100_mbox_priv(cp->chan->mbox);
|
||||
spin_lock_irqsave(&priv->mbox_lock, flags);
|
||||
val = p100_mbox_chan_read(cp, off, is_remote);
|
||||
val &= ~clr;
|
||||
val |= set;
|
||||
p100_mbox_chan_write(cp, val, off, is_remote);
|
||||
spin_unlock_irqrestore(&priv->mbox_lock, flags);
|
||||
}
|
||||
|
||||
static void p100_mbox_chan_rd_data(struct p100_mbox_con_priv *cp,
|
||||
void *data, bool is_remote)
|
||||
{
|
||||
u32 i;
|
||||
u32 *arg = data;
|
||||
u32 off = P100_MBOX_INFO0;
|
||||
|
||||
/* read info0 ~ info6, totally 28 bytes
|
||||
* requires data memory size is 28 bytes
|
||||
*/
|
||||
for (i = 0; i < P100_MBOX_DATA_INFO_NUM; i++) {
|
||||
*arg = p100_mbox_chan_read(cp, off, is_remote);
|
||||
off += 4;
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
|
||||
static void p100_mbox_chan_wr_data(struct p100_mbox_con_priv *cp,
|
||||
void *data, bool is_remote)
|
||||
{
|
||||
u32 i;
|
||||
u32 *arg = data;
|
||||
u32 off = P100_MBOX_INFO0;
|
||||
|
||||
/* write info0 ~ info6, totally 28 bytes
|
||||
* requires data memory is 28 bytes valid data
|
||||
*/
|
||||
for (i = 0; i < P100_MBOX_DATA_INFO_NUM; i++) {
|
||||
p100_mbox_chan_write(cp, *arg, off, is_remote);
|
||||
off += 4;
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
|
||||
static void p100_mbox_chan_wr_ack(struct p100_mbox_con_priv *cp,
|
||||
void *data, bool is_remote)
|
||||
{
|
||||
u32 *arg = data;
|
||||
u32 off = P100_MBOX_INFO7;
|
||||
|
||||
p100_mbox_chan_write(cp, *arg, off, is_remote);
|
||||
}
|
||||
|
||||
static int p100_mbox_chan_id_to_mapbit(struct p100_mbox_con_priv *cp)
|
||||
{
|
||||
int i;
|
||||
int mapbit = 0;
|
||||
for (i = 0; i < P100_MBOX_CHANS; i++) {
|
||||
if (i == cp->idx)
|
||||
return mapbit;
|
||||
|
||||
if (i != P100_MBOX_INTERRUPT)
|
||||
mapbit++;
|
||||
}
|
||||
|
||||
if (i == P100_MBOX_CHANS)
|
||||
dev_err(cp->chan->mbox->dev, "convert to mapbit failed\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void p100_mbox_txdb_tasklet(unsigned long data)
|
||||
{
|
||||
struct p100_mbox_con_priv *cp = (struct p100_mbox_con_priv *)data;
|
||||
|
||||
mbox_chan_txdone(cp->chan, 0);
|
||||
}
|
||||
|
||||
static irqreturn_t p100_mbox_isr(int irq, void *p)
|
||||
{
|
||||
u32 info0_data, info7_data;
|
||||
u32 sta, dat[P100_MBOX_DATA_INFO_NUM];
|
||||
u32 ack_magic = P100_MBOX_ACK_MAGIC;
|
||||
struct mbox_chan *chan = p;
|
||||
struct p100_mbox_con_priv *cp = chan->con_priv;
|
||||
int mapbit = p100_mbox_chan_id_to_mapbit(cp);
|
||||
struct p100_mbox_priv *priv = to_p100_mbox_priv(chan->mbox);
|
||||
|
||||
sta = p100_mbox_read(priv, P100_MBOX_STA);
|
||||
if (!(sta & BIT(mapbit)))
|
||||
return IRQ_NONE;
|
||||
/* clear chan irq bit in STA register */
|
||||
p100_mbox_rmw(priv, P100_MBOX_CLR, BIT(mapbit), 0);
|
||||
/* rx doorbell */
|
||||
if (cp->type == P100_MBOX_TYPE_DB) {
|
||||
mbox_chan_received_data(cp->chan, NULL);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
/* info0 is the protocol word, should not be zero! */
|
||||
info0_data = p100_mbox_chan_read(cp, P100_MBOX_INFO0, false);
|
||||
if (info0_data) {
|
||||
/* read info0~info6 data */
|
||||
p100_mbox_chan_rd_data(cp, dat, false);
|
||||
|
||||
/* clear local info0 */
|
||||
p100_mbox_chan_write(cp, 0x0, P100_MBOX_INFO0, false);
|
||||
/* notify remote cpu */
|
||||
p100_mbox_chan_wr_ack(cp, &ack_magic, true);
|
||||
/* transfer the data to client */
|
||||
mbox_chan_received_data(chan, (void *)dat);
|
||||
}
|
||||
/* info7 magic value mean the real ack signal, not generate bit7 */
|
||||
info7_data = p100_mbox_chan_read(cp, P100_MBOX_INFO7, false);
|
||||
if (info7_data == P100_MBOX_ACK_MAGIC) {
|
||||
/* clear local info7 */
|
||||
p100_mbox_chan_write(cp, 0x0, P100_MBOX_INFO7, false);
|
||||
|
||||
/* notify framework the last TX has completed */
|
||||
mbox_chan_txdone(chan, 0);
|
||||
}
|
||||
if (!info0_data && !info7_data)
|
||||
return IRQ_NONE;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int p100_mbox_send_data(struct mbox_chan *chan, void *data)
|
||||
{
|
||||
struct p100_mbox_con_priv *cp = chan->con_priv;
|
||||
if (cp->type == P100_MBOX_TYPE_DB)
|
||||
tasklet_schedule(&cp->txdb_tasklet);
|
||||
else
|
||||
p100_mbox_chan_wr_data(cp, data, true);
|
||||
p100_mbox_chan_rmw(cp, P100_MBOX_GEN, P100_MBOX_GEN_RX_DATA, 0,
|
||||
true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int p100_mbox_startup(struct mbox_chan *chan)
|
||||
{
|
||||
int ret;
|
||||
int mask_bit;
|
||||
u32 data[8] = {0};
|
||||
struct p100_mbox_con_priv *cp = chan->con_priv;
|
||||
struct p100_mbox_priv *priv = to_p100_mbox_priv(chan->mbox);
|
||||
/* clear local and remote generate and info0~info7 */
|
||||
p100_mbox_chan_rmw(cp, P100_MBOX_GEN, 0x0, 0xff, true);
|
||||
p100_mbox_chan_rmw(cp, P100_MBOX_GEN, 0x0, 0xff, false);
|
||||
p100_mbox_chan_wr_ack(cp, &data[7], true);
|
||||
p100_mbox_chan_wr_ack(cp, &data[7], false);
|
||||
p100_mbox_chan_wr_data(cp, &data[0], true);
|
||||
p100_mbox_chan_wr_data(cp, &data[0], false);
|
||||
/* enable the chan mask */
|
||||
mask_bit = p100_mbox_chan_id_to_mapbit(cp);
|
||||
p100_mbox_rmw(priv, P100_MBOX_MASK, BIT(mask_bit), 0);
|
||||
|
||||
if (cp->type == P100_MBOX_TYPE_DB)
|
||||
/* tx doorbell doesn't have ACK, rx doorbell requires isr */
|
||||
tasklet_init(&cp->txdb_tasklet, p100_mbox_txdb_tasklet,
|
||||
(unsigned long)cp);
|
||||
ret = request_irq(priv->irq, p100_mbox_isr, IRQF_SHARED |
|
||||
IRQF_NO_SUSPEND, cp->irq_desc, chan);
|
||||
if (ret) {
|
||||
dev_err(priv->dev,
|
||||
"Unable to acquire IRQ %d\n", priv->irq);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void p100_mbox_shutdown(struct mbox_chan *chan)
|
||||
{
|
||||
int mask_bit;
|
||||
struct p100_mbox_con_priv *cp = chan->con_priv;
|
||||
struct p100_mbox_priv *priv = to_p100_mbox_priv(chan->mbox);
|
||||
|
||||
/* clear the chan mask */
|
||||
mask_bit = p100_mbox_chan_id_to_mapbit(cp);
|
||||
p100_mbox_rmw(priv, P100_MBOX_MASK, 0, BIT(mask_bit));
|
||||
|
||||
free_irq(priv->irq, chan);
|
||||
}
|
||||
|
||||
static const struct mbox_chan_ops p100_mbox_ops = {
|
||||
.send_data = p100_mbox_send_data,
|
||||
.startup = p100_mbox_startup,
|
||||
.shutdown = p100_mbox_shutdown,
|
||||
};
|
||||
|
||||
static int p100_mbox_init_generic(struct p100_mbox_priv *priv)
|
||||
{
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
priv->ctx = devm_kzalloc(priv->dev, sizeof(*priv->ctx), GFP_KERNEL);
|
||||
if (!priv->ctx)
|
||||
return -ENOMEM;
|
||||
#endif
|
||||
/* Set default configuration */
|
||||
p100_mbox_write(priv, 0xff, P100_MBOX_CLR);
|
||||
p100_mbox_write(priv, 0x0, P100_MBOX_MASK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mbox_chan *p100_mbox_xlate(struct mbox_controller *mbox,
|
||||
const struct of_phandle_args *sp)
|
||||
{
|
||||
u32 chan, type;
|
||||
struct p100_mbox_con_priv *cp;
|
||||
|
||||
if (sp->args_count != 2) {
|
||||
dev_err(mbox->dev,
|
||||
"Invalid argument count %d\n", sp->args_count);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
chan = sp->args[0]; /* comm remote channel */
|
||||
type = sp->args[1]; /* comm channel type */
|
||||
if (chan >= mbox->num_chans) {
|
||||
dev_err(mbox->dev, "Not supported channel number: %d\n", chan);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (type > P100_MBOX_TYPE_DB) {
|
||||
dev_err(mbox->dev,
|
||||
"Not supported the type for channel[%d]\n", chan);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
cp = mbox->chans[chan].con_priv;
|
||||
cp->type = type;
|
||||
|
||||
return &mbox->chans[chan];
|
||||
}
|
||||
|
||||
static int p100_mbox_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
unsigned int i;
|
||||
struct resource *res;
|
||||
struct p100_mbox_priv *priv;
|
||||
unsigned int remote_idx = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
if (of_property_read_u32(np, "icu_cpu_id", &priv->cur_icu_cpu_id)) {
|
||||
dev_err(dev, "icu_cpu_id is missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
priv->dev = dev;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "interrupt_addr");
|
||||
priv->local_icu[P100_MBOX_INTERRUPT] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->local_icu[P100_MBOX_INTERRUPT]))
|
||||
return PTR_ERR(priv->local_icu[P100_MBOX_INTERRUPT]);
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "local_addr0");
|
||||
priv->local_icu[P100_MBOX_DATA_CH0] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->local_icu[P100_MBOX_DATA_CH0]))
|
||||
return PTR_ERR(priv->local_icu[P100_MBOX_DATA_CH0]);
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu0");
|
||||
priv->remote_icu[P100_MBOX_REMOTE_CH0] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->remote_icu[P100_MBOX_REMOTE_CH0]))
|
||||
return PTR_ERR(priv->remote_icu[P100_MBOX_REMOTE_CH0]);
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "local_addr1");
|
||||
if(res!=NULL) {
|
||||
priv->local_icu[P100_MBOX_DATA_CH1] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->local_icu[P100_MBOX_DATA_CH1]))
|
||||
return PTR_ERR(priv->local_icu[P100_MBOX_DATA_CH1]);
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "remote_icu1");
|
||||
if(res!=NULL) {
|
||||
priv->remote_icu[P100_MBOX_REMOTE_CH1] = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(priv->remote_icu[P100_MBOX_REMOTE_CH1]))
|
||||
return PTR_ERR(priv->remote_icu[P100_MBOX_REMOTE_CH1]);
|
||||
}
|
||||
|
||||
priv->cur_cpu_ch_base = priv->local_icu[P100_MBOX_INTERRUPT];
|
||||
priv->irq = platform_get_irq(pdev, 0);
|
||||
if (priv->irq < 0)
|
||||
return priv->irq;
|
||||
priv->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(priv->clk)) {
|
||||
if (PTR_ERR(priv->clk) != -ENOENT)
|
||||
return PTR_ERR(priv->clk);
|
||||
priv->clk = NULL;
|
||||
}
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
/* init the chans */
|
||||
for (i = 0; i < P100_MBOX_CHANS; i++) {
|
||||
struct p100_mbox_con_priv *cp = &priv->con_priv[i];
|
||||
cp->idx = i;
|
||||
cp->chan = &priv->mbox_chans[i];
|
||||
priv->mbox_chans[i].con_priv = cp;
|
||||
snprintf(cp->irq_desc, sizeof(cp->irq_desc),
|
||||
"p100_mbox_chan[%i]", cp->idx);
|
||||
cp->comm_local_base = priv->local_icu[i];
|
||||
if (i != P100_MBOX_INTERRUPT) {
|
||||
cp->comm_remote_base = priv->remote_icu[remote_idx];
|
||||
remote_idx++;
|
||||
}
|
||||
}
|
||||
spin_lock_init(&priv->mbox_lock);
|
||||
|
||||
priv->mbox.dev = dev;
|
||||
priv->mbox.ops = &p100_mbox_ops;
|
||||
priv->mbox.chans = priv->mbox_chans;
|
||||
priv->mbox.num_chans = P100_MBOX_CHANS;
|
||||
priv->mbox.of_xlate = p100_mbox_xlate;
|
||||
priv->mbox.txdone_irq = true;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
ret = p100_mbox_init_generic(priv);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to init mailbox context\n");
|
||||
return ret;
|
||||
}
|
||||
return devm_mbox_controller_register(dev, &priv->mbox);
|
||||
}
|
||||
|
||||
static int p100_mbox_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct p100_mbox_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id p100_mbox_dt_ids[] = {
|
||||
{ .compatible = "zhihe,p100-mbox" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, p100_mbox_dt_ids);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int __maybe_unused p100_mbox_suspend_noirq(struct device *dev)
|
||||
{
|
||||
u32 i;
|
||||
struct p100_mbox_priv *priv = dev_get_drvdata(dev);
|
||||
struct p100_mbox_context *ctx = priv->ctx;
|
||||
|
||||
/*
|
||||
* ONLY interrupt mask bit should be stored and restores.
|
||||
* INFO data all assumed to be lost.
|
||||
*/
|
||||
for (i = 0 ; i < P100_MBOX_CHANS; i++)
|
||||
ctx->intr_mask[i] = ioread32(priv->local_icu[i] +
|
||||
P100_MBOX_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused p100_mbox_resume_noirq(struct device *dev)
|
||||
{
|
||||
u32 i;
|
||||
struct p100_mbox_priv *priv = dev_get_drvdata(dev);
|
||||
struct p100_mbox_context *ctx = priv->ctx;
|
||||
|
||||
for (i = 0 ; i < P100_MBOX_CHANS; i++)
|
||||
iowrite32(ctx->intr_mask[i],
|
||||
priv->local_icu[i] + P100_MBOX_MASK);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int __maybe_unused p100_mbox_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct p100_mbox_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused p100_mbox_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct p100_mbox_priv *priv = dev_get_drvdata(dev);
|
||||
int ret = clk_prepare_enable(priv->clk);
|
||||
|
||||
if (ret)
|
||||
dev_err(dev, "failed to enable clock\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops p100_mbox_pm_ops = {
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(p100_mbox_suspend_noirq,
|
||||
p100_mbox_resume_noirq)
|
||||
#endif
|
||||
SET_RUNTIME_PM_OPS(p100_mbox_runtime_suspend,
|
||||
p100_mbox_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver p100_mbox_driver = {
|
||||
.probe = p100_mbox_probe,
|
||||
.remove = p100_mbox_remove,
|
||||
.driver = {
|
||||
.name = "p100_mbox",
|
||||
.of_match_table = p100_mbox_dt_ids,
|
||||
.pm = &p100_mbox_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(p100_mbox_driver);
|
||||
|
||||
MODULE_AUTHOR("xionglue.huang <huangxionglue@zhcomputing.com>");
|
||||
MODULE_DESCRIPTION("p100 Mailbox IPC driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -3114,6 +3114,10 @@ static bool sdhci_request_done(struct sdhci_host *host)
|
||||
sdhci_reset_for(host, REQUEST_ERROR);
|
||||
|
||||
host->pending_reset = false;
|
||||
|
||||
/* Clear any pending interrupts after reset */
|
||||
sdhci_writel(host, SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK,
|
||||
SDHCI_INT_STATUS);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -378,7 +378,7 @@ static const struct flexcan_devtype_data fsl_lx2160a_r1_devtype_data = {
|
||||
FLEXCAN_QUIRK_SUPPORT_RX_MAILBOX_RTR,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_a210_devtype_data = {
|
||||
static const struct flexcan_devtype_data fsl_zhihe_a210_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
|
||||
FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
|
||||
FLEXCAN_QUIRK_USE_RX_MAILBOX | FLEXCAN_QUIRK_SUPPORT_FD |
|
||||
@@ -2027,7 +2027,7 @@ static const struct of_device_id flexcan_of_match[] = {
|
||||
{ .compatible = "fsl,vf610-flexcan", .data = &fsl_vf610_devtype_data, },
|
||||
{ .compatible = "fsl,ls1021ar2-flexcan", .data = &fsl_ls1021a_r2_devtype_data, },
|
||||
{ .compatible = "fsl,lx2160ar1-flexcan", .data = &fsl_lx2160a_r1_devtype_data, },
|
||||
{ .compatible = "fsl,a210-flexcan", .data = &fsl_a210_devtype_data, },
|
||||
{ .compatible = "fsl,zha210-flexcan", .data = &fsl_zhihe_a210_devtype_data, },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, flexcan_of_match);
|
||||
|
||||
@@ -433,7 +433,7 @@ config NVMEM_ZH_EFUSE
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Say Y here to include support for Thead efuse found on found on
|
||||
P100 fullmask devices
|
||||
A210 fullmask devices
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called nvmem-zh-efuse.
|
||||
|
||||
|
||||
@@ -478,14 +478,14 @@ config PINCTRL_TH1520
|
||||
help
|
||||
This selects the pinctrl driver for XuanTie TH1520 RISC-V SoC.
|
||||
|
||||
config PINCTRL_P100
|
||||
tristate "Pinctrl driver for the ZhiHe P100 SoC"
|
||||
config PINCTRL_A210
|
||||
tristate "Pinctrl driver for the ZhiHe A210 SoC"
|
||||
depends on ARCH_ZHIHE || COMPILE_TEST
|
||||
select GENERIC_PINMUX_FUNCTIONS
|
||||
select GENERIC_PINCONF
|
||||
select PINMUX
|
||||
help
|
||||
This selects the pinctrl driver for ZhiHe P100 RISC-V SoC.
|
||||
This selects the pinctrl driver for ZhiHe A210 RISC-V SoC.
|
||||
|
||||
config PINCTRL_ZYNQ
|
||||
bool "Pinctrl driver for Xilinx Zynq"
|
||||
|
||||
@@ -49,7 +49,7 @@ obj-$(CONFIG_PINCTRL_STMFX) += pinctrl-stmfx.o
|
||||
obj-$(CONFIG_PINCTRL_SX150X) += pinctrl-sx150x.o
|
||||
obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o
|
||||
obj-$(CONFIG_PINCTRL_TH1520) += pinctrl-th1520.o
|
||||
obj-$(CONFIG_PINCTRL_P100) += pinctrl-p100.o
|
||||
obj-$(CONFIG_PINCTRL_A210) += pinctrl-a210.o
|
||||
obj-$(CONFIG_PINCTRL_ZYNQMP) += pinctrl-zynqmp.o
|
||||
obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_P100_POWER_DOMAIN) += p100-pd.o
|
||||
obj-$(CONFIG_A210_POWER_DOMAIN) += a210-pd.o
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <dt-bindings/iopmp/zh-iopmp.h>
|
||||
#include <asm/zh-iopmp.h>
|
||||
|
||||
#include "p100-pd.h"
|
||||
#include "a210-pd.h"
|
||||
|
||||
static const struct p100_pd_range p100_pd_ranges[] = {
|
||||
{"power_gpu", P100_PD_GPU},
|
||||
@@ -3,8 +3,8 @@
|
||||
* Copyright (C) 2025 Zhihe Computing Limited.
|
||||
*/
|
||||
|
||||
#ifndef __P100_PD_H
|
||||
#define __P100_PD_H
|
||||
#ifndef __A210_PD_H
|
||||
#define __A210_PD_H
|
||||
|
||||
#define P100_PD_NAME_SIZE 20
|
||||
#define P100_PD_STATE_NAME_SIZE 10
|
||||
@@ -328,12 +328,12 @@ config RESET_ZYNQ
|
||||
help
|
||||
This enables the reset controller driver for Xilinx Zynq SoCs.
|
||||
|
||||
config RESET_P100
|
||||
bool "P100 Reset Driver"
|
||||
config RESET_A210
|
||||
bool "A210 Reset Driver"
|
||||
depends on ARCH_ZHIHE
|
||||
default y
|
||||
help
|
||||
Build the driver for zhihe p100 Reset Driver
|
||||
Build the driver for ZhiHe A210 Reset Driver
|
||||
|
||||
source "drivers/reset/starfive/Kconfig"
|
||||
source "drivers/reset/sti/Kconfig"
|
||||
|
||||
@@ -42,4 +42,4 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
|
||||
obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
|
||||
obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
|
||||
obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
|
||||
obj-$(CONFIG_RESET_P100) += reset-p100.o
|
||||
obj-$(CONFIG_RESET_A210) += reset-a210.o
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset-controller.h>
|
||||
#include <linux/io.h>
|
||||
#include <dt-bindings/reset/p100-reset.h>
|
||||
#include <dt-bindings/reset/a210-reset.h>
|
||||
|
||||
|
||||
#define P100_RST_NAME_SIZE 20
|
||||
@@ -2,24 +2,24 @@
|
||||
|
||||
menu "ZHIHE SoC drivers"
|
||||
|
||||
config P100_MEMTESTER
|
||||
tristate "ZHIHE P100 memtester support"
|
||||
config A210_MEMTESTER
|
||||
tristate "ZHIHE A210 memtester support"
|
||||
default y
|
||||
help
|
||||
This driver supports P100 memtester feature.
|
||||
This driver supports A210 memtester feature.
|
||||
|
||||
config P100_POWER_DOMAIN
|
||||
bool "P100 Power Domain driver"
|
||||
config A210_POWER_DOMAIN
|
||||
bool "A210 Power Domain driver"
|
||||
depends on PM
|
||||
select PM_GENERIC_DOMAINS
|
||||
default y
|
||||
help
|
||||
This is the power domain driver that controls PCU/PPU for P100 Soc.
|
||||
This is the power domain driver that controls PCU/PPU for A210 Soc.
|
||||
|
||||
config P100_BMU
|
||||
tristate "p100-bmu driver"
|
||||
config A210_BMU
|
||||
tristate "A210 bmu driver"
|
||||
default n
|
||||
help
|
||||
This driver provides support for p100 bmu.
|
||||
This driver provides support for A210 bmu.
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_P100_MEMTESTER) += p100-memtester.o
|
||||
obj-$(CONFIG_P100_BMU) += p100-bmu.o
|
||||
obj-$(CONFIG_A210_MEMTESTER) += a210-memtester.o
|
||||
obj-$(CONFIG_A210_BMU) += a210-bmu.o
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef _P100_BMU_TYPE_H
|
||||
#define _P100_BMU_TYPE_H
|
||||
#ifndef _A210_BMU_TYPE_H
|
||||
#define _A210_BMU_TYPE_H
|
||||
#include <linux/kernel.h>
|
||||
//#include <linux/spinlock.h>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#define TRACE_SYSTEM bmu
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
#include "p100_bmu_type.h"
|
||||
#include "a210_bmu_type.h"
|
||||
|
||||
TRACE_EVENT (bmu_cnt_bytes_cycle_trans,
|
||||
TP_PROTO (char *name, u8 ch, pft_event_array_t * pft_event),
|
||||
|
||||
@@ -87,7 +87,8 @@ static int dw_qspi_mmio_probe(struct platform_device *pdev)
|
||||
struct dw_qspi_mmio *dwsmmio;
|
||||
struct dw_spi *dws;
|
||||
int ret;
|
||||
int num_cs,rx_sample_dly;
|
||||
u32 num_cs, rx_sample_dly = 4;
|
||||
u32 swap_data = 0;
|
||||
|
||||
dwsmmio = devm_kzalloc(&pdev->dev, sizeof(struct dw_qspi_mmio),
|
||||
GFP_KERNEL);
|
||||
@@ -150,10 +151,14 @@ static int dw_qspi_mmio_probe(struct platform_device *pdev)
|
||||
num_cs = 1;
|
||||
device_property_read_u32(&pdev->dev, "num-cs", &num_cs);
|
||||
dws->num_cs = num_cs;
|
||||
rx_sample_dly = 4;
|
||||
|
||||
device_property_read_u32(&pdev->dev, "rx-sample-dly", &rx_sample_dly);
|
||||
printk("get gpio succes %d\n",rx_sample_dly);
|
||||
dev_dbg(&pdev->dev, "get rx_sample_dly success %d\n", rx_sample_dly);
|
||||
dws->rx_sample_delay = rx_sample_dly;
|
||||
|
||||
device_property_read_u32(&pdev->dev, "spi-swap-data", &swap_data);
|
||||
dws->swap_data = swap_data;
|
||||
|
||||
init_func = device_get_match_data(&pdev->dev);
|
||||
if (init_func) {
|
||||
ret = init_func(pdev, dwsmmio);
|
||||
|
||||
@@ -272,10 +272,17 @@ static void dw_writer(struct dw_spi *dws)
|
||||
if (dws->tx_end - dws->len) {
|
||||
if (dws->n_bytes == 1)
|
||||
txw = *(u8 *)(dws->tx);
|
||||
else if(dws->n_bytes == 2)
|
||||
txw = *(u16 *)(dws->tx);
|
||||
else
|
||||
txw = *(u32 *)(dws->tx);
|
||||
else if(dws->n_bytes == 2) {
|
||||
if (dws->swap_data)
|
||||
txw = swab16(*(u16 *)(dws->tx));
|
||||
else
|
||||
txw = *(u16 *)(dws->tx);
|
||||
} else {
|
||||
if (dws->swap_data)
|
||||
txw = swab32(*(u32 *)(dws->tx));
|
||||
else
|
||||
txw = *(u32 *)(dws->tx);
|
||||
}
|
||||
}
|
||||
dw_write_io_reg(dws, DW_SPI_DR, txw);
|
||||
dws->tx += dws->n_bytes;
|
||||
@@ -296,10 +303,17 @@ static void dw_reader(struct dw_spi *dws)
|
||||
if (dws->rx_end - dws->len) {
|
||||
if (dws->n_bytes == 1)
|
||||
*(u8 *)(dws->rx) = rxw;
|
||||
else if(dws->n_bytes ==2)
|
||||
*(u16 *)(dws->rx) = rxw;
|
||||
else
|
||||
*(u32 *)(dws->rx) = rxw;
|
||||
else if(dws->n_bytes == 2) {
|
||||
if (dws->swap_data)
|
||||
*(u16 *)(dws->rx) = swab16(rxw);
|
||||
else
|
||||
*(u16 *)(dws->rx) = rxw;
|
||||
} else {
|
||||
if (dws->swap_data)
|
||||
*(u32 *)(dws->rx) = swab32(rxw);
|
||||
else
|
||||
*(u32 *)(dws->rx) = rxw;
|
||||
}
|
||||
}
|
||||
dws->rx += dws->n_bytes;
|
||||
}
|
||||
|
||||
@@ -199,9 +199,10 @@ struct dw_spi {
|
||||
|
||||
int cs_override;
|
||||
u32 reg_io_width; /* DR I/O width in bytes */
|
||||
u16 bus_num;
|
||||
u16 num_cs; /* supported slave numbers */
|
||||
u16 rx_sample_delay;/* timing value for rx sample delay */
|
||||
u32 bus_num;
|
||||
u32 num_cs; /* supported slave numbers */
|
||||
u32 rx_sample_delay;/* timing value for rx sample delay */
|
||||
u32 swap_data;
|
||||
struct gpio_desc *slave_cs; /* gpio cs handle */
|
||||
void (*set_cs)(struct spi_device *spi, bool enable);
|
||||
/* used by spi_controller_mem_ops interface */
|
||||
|
||||
@@ -2057,7 +2057,21 @@ config TH1520_PMIC_WATCHDOG
|
||||
module will be called acquirewdt.
|
||||
|
||||
Most people will say N.
|
||||
|
||||
config A210_WATCHDOG
|
||||
tristate "A210 watchdog"
|
||||
depends on A210_MBOX
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
This is the driver for the hardware watchdog on A210 Board. This watchdog
|
||||
simply watches your kernel to make sure it doesn't freeze, and if
|
||||
it does, it reboots your computer after a certain amount of time.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called acquirewdt.
|
||||
|
||||
Most people will say N.
|
||||
|
||||
# S390 Architecture
|
||||
|
||||
config DIAG288_WATCHDOG
|
||||
|
||||
@@ -197,6 +197,7 @@ obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
|
||||
# RISC-V Architecture
|
||||
obj-$(CONFIG_STARFIVE_WATCHDOG) += starfive-wdt.o
|
||||
obj-$(CONFIG_TH1520_PMIC_WATCHDOG) += th1520_wdt.o
|
||||
obj-$(CONFIG_A210_WATCHDOG) += a210_wdt.o
|
||||
|
||||
# S390 Architecture
|
||||
obj-$(CONFIG_DIAG288_WATCHDOG) += diag288_wdt.o
|
||||
|
||||
437
drivers/watchdog/a210_wdt.c
Executable file
437
drivers/watchdog/a210_wdt.c
Executable file
@@ -0,0 +1,437 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2021-2024 Alibaba Group Holding Limited.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/firmware/zhihe/ipc.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define DRV_NAME "a210-wdt"
|
||||
|
||||
/*
|
||||
* Watchdog selector to timeout in seconds.
|
||||
* 0: WDT disabled;
|
||||
* others: timeout = 2048 ms * 2^(TWDSCALE-1).
|
||||
*/
|
||||
static const unsigned int wdt_timeout[] = {8, 16, 32,128};
|
||||
#define A210_TWDSCALE_DISABLE 0
|
||||
#define A210_TWDSCALE_MIN 1
|
||||
#define A210_TWDSCALE_MAX (ARRAY_SIZE(wdt_timeout) - 1)
|
||||
#define A210_WDT_MIN_TIMEOUT wdt_timeout[A210_TWDSCALE_MIN]
|
||||
#define A210_WDT_MAX_TIMEOUT wdt_timeout[A210_TWDSCALE_MAX]
|
||||
#define A210_WDT_TIMEOUT wdt_timeout[3]
|
||||
#define A210_RESET_PROTECTION_MS 256
|
||||
|
||||
struct a210_aon_msg_wdg_ctrl {
|
||||
struct a210_aon_rpc_msg_hdr hdr;
|
||||
u32 timeout;
|
||||
u32 running_state;
|
||||
u32 reserved[1];
|
||||
} __packed __aligned(1);
|
||||
|
||||
struct a210_aon_msg_wdg_ctrl_ack {
|
||||
struct a210_aon_rpc_ack_common ack_hdr;
|
||||
u32 timeout;
|
||||
u32 running_state;
|
||||
u32 reserved[1];
|
||||
} __packed __aligned(1);
|
||||
|
||||
struct a210_wdt_device {
|
||||
struct device *dev;
|
||||
struct a210_aon_ipc *ipc_handle;
|
||||
struct a210_aon_msg_wdg_ctrl msg;
|
||||
unsigned int is_aon_wdt_ena;
|
||||
};
|
||||
|
||||
struct a210_wdt_device *a210_power_off_wdt;
|
||||
|
||||
static unsigned int a210_wdt_timeout_to_sel(unsigned secs)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = A210_TWDSCALE_MIN; i <= A210_TWDSCALE_MAX; i++) {
|
||||
if (wdt_timeout[i] >= secs)
|
||||
return i;
|
||||
}
|
||||
|
||||
return A210_TWDSCALE_MAX;
|
||||
}
|
||||
|
||||
static void a210_wdt_msg_hdr_fill(struct a210_aon_rpc_msg_hdr *hdr, enum a210_aon_wdg_func func)
|
||||
{
|
||||
hdr->svc = (uint8_t)A210_AON_RPC_SVC_WDG;
|
||||
hdr->func = (uint8_t)func;
|
||||
hdr->size = A210_AON_RPC_MSG_NUM;
|
||||
}
|
||||
|
||||
static int a210_wdt_is_running(struct a210_wdt_device *wdt_dev)
|
||||
{
|
||||
struct a210_aon_ipc *ipc = wdt_dev->ipc_handle;
|
||||
struct a210_aon_msg_wdg_ctrl_ack ack_msg= {0};
|
||||
int ret;
|
||||
|
||||
a210_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, A210_AON_WDG_FUNC_GET_STATE);
|
||||
wdt_dev->msg.running_state = -1;
|
||||
|
||||
ret = a210_aon_call_rpc(ipc, &wdt_dev->msg, &ack_msg, true);
|
||||
printk("a210_wdt_is_running ret %d",ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
//RPC_GET_BE32(&ack_msg.timeout, 0, &wdt_dev->msg.timeout);
|
||||
RPC_GET_BE32(&ack_msg.timeout, 4, &wdt_dev->msg.running_state);
|
||||
|
||||
pr_debug("ret = %d, timeout = %d, running_state = %d\n", ret, wdt_dev->msg.timeout,
|
||||
wdt_dev->msg.running_state);
|
||||
printk("ret = %d, timeout = %d, running_state = %d\n", ret, wdt_dev->msg.timeout,
|
||||
wdt_dev->msg.running_state);
|
||||
return wdt_dev->msg.running_state;
|
||||
}
|
||||
|
||||
static int a210_wdt_update_timeout(struct a210_wdt_device *wdt_dev, unsigned int timeout)
|
||||
{
|
||||
/*
|
||||
* The watchdog triggers a reboot if a timeout value is already
|
||||
* programmed because the timeout value combines two functions
|
||||
* in one: indicating the counter limit and starting the watchdog.
|
||||
* The watchdog must be disabled to be able to change the timeout
|
||||
* value if the watchdog is already running. Then we can set the
|
||||
* new timeout value which enables the watchdog again.
|
||||
*/
|
||||
struct a210_aon_ipc *ipc = wdt_dev->ipc_handle;
|
||||
struct a210_aon_msg_wdg_ctrl_ack ack_msg= {0};
|
||||
int ret;
|
||||
|
||||
a210_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, A210_AON_WDG_FUNC_TIMEOUTSET);
|
||||
|
||||
RPC_SET_BE32(&wdt_dev->msg.timeout, 0 , timeout);
|
||||
|
||||
ret = a210_aon_call_rpc(ipc, &wdt_dev->msg, &ack_msg, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a210_wdt_set_timeout(struct watchdog_device *wdd, unsigned int timeout)
|
||||
{
|
||||
struct a210_wdt_device *wdt_dev = watchdog_get_drvdata(wdd);
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* There are two cases when a set_timeout() will be called:
|
||||
* 1. The watchdog is off and someone wants to set the timeout for the
|
||||
* further use.
|
||||
* 2. The watchdog is already running and a new timeout value should be
|
||||
* set.
|
||||
*
|
||||
* The watchdog can't store a timeout value not equal zero without
|
||||
* enabling the watchdog, so the timeout must be buffered by the driver.
|
||||
*/
|
||||
if (watchdog_active(wdd))
|
||||
ret = a210_wdt_update_timeout(wdt_dev, timeout);
|
||||
else
|
||||
wdd->timeout = wdt_timeout[a210_wdt_timeout_to_sel(timeout)];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int a210_wdt_start(struct watchdog_device *wdd)
|
||||
{
|
||||
struct a210_wdt_device *wdt_dev = watchdog_get_drvdata(wdd);
|
||||
struct a210_aon_ipc *ipc = wdt_dev->ipc_handle;
|
||||
struct a210_aon_rpc_ack_common ack_msg = {0};
|
||||
int ret;
|
||||
|
||||
a210_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, A210_AON_WDG_FUNC_START);
|
||||
|
||||
ret = a210_aon_call_rpc(ipc, &wdt_dev->msg, &ack_msg, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a210_wdt_stop(struct watchdog_device *wdd)
|
||||
{
|
||||
struct a210_wdt_device *wdt_dev = watchdog_get_drvdata(wdd);
|
||||
struct a210_aon_ipc *ipc = wdt_dev->ipc_handle;
|
||||
struct a210_aon_rpc_ack_common ack_msg = {0};
|
||||
int ret;
|
||||
|
||||
a210_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, A210_AON_WDG_FUNC_STOP);
|
||||
|
||||
ret = a210_aon_call_rpc(ipc, &wdt_dev->msg, &ack_msg, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a210_wdt_ping(struct watchdog_device *wdd)
|
||||
{
|
||||
struct a210_wdt_device *wdt_dev = watchdog_get_drvdata(wdd);
|
||||
struct a210_aon_ipc *ipc = wdt_dev->ipc_handle;
|
||||
struct a210_aon_rpc_ack_common ack_msg = {0};
|
||||
int ret;
|
||||
|
||||
a210_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, A210_AON_WDG_FUNC_PING);
|
||||
|
||||
ret = a210_aon_call_rpc(ipc, &wdt_dev->msg, &ack_msg, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a210_wdt_restart(struct watchdog_device *wdd, unsigned long action, void *data)
|
||||
{
|
||||
struct a210_wdt_device *wdt_dev = watchdog_get_drvdata(wdd);
|
||||
struct a210_aon_ipc *ipc = wdt_dev->ipc_handle;
|
||||
int ret;
|
||||
|
||||
a210_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, A210_AON_WDG_FUNC_RESTART);
|
||||
|
||||
pr_debug("[%s,%d]: Inform aon to restart the whole system....\n", __func__, __LINE__);
|
||||
printk("a210_wdt_restart msg 0x%x\n",wdt_dev->msg.hdr);
|
||||
ret = a210_aon_call_rpc(ipc, &wdt_dev->msg, NULL, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
pr_debug("[%s,%d]: Finish to inform aon to restart the whole system....\n", __func__, __LINE__);
|
||||
printk("Finish to inform aon to restart the whole system....\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct watchdog_info a210_watchdog_info = {
|
||||
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
|
||||
.identity = "p100 Watchdog",
|
||||
};
|
||||
|
||||
|
||||
static const struct watchdog_ops a210_watchdog_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = a210_wdt_start,
|
||||
.stop = a210_wdt_stop,
|
||||
.ping = a210_wdt_ping,
|
||||
.set_timeout = a210_wdt_set_timeout,
|
||||
.restart = a210_wdt_restart,
|
||||
};
|
||||
|
||||
static ssize_t aon_sys_wdt_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct a210_wdt_device *wdt_dev = platform_get_drvdata(pdev);
|
||||
return sprintf(buf,"%u\n",wdt_dev->is_aon_wdt_ena);
|
||||
}
|
||||
|
||||
static ssize_t aon_sys_wdt_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct a210_wdt_device *wdt_dev = platform_get_drvdata(pdev);
|
||||
struct a210_aon_rpc_ack_common ack_msg = {0};
|
||||
struct a210_aon_ipc *ipc;
|
||||
int ret;
|
||||
char *start = (char *)buf;
|
||||
unsigned long val;
|
||||
|
||||
ipc = wdt_dev->ipc_handle;
|
||||
val = simple_strtoul(start, &start, 0);
|
||||
wdt_dev->is_aon_wdt_ena = val;
|
||||
if (val)
|
||||
a210_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, A210_AON_WDG_FUNC_AON_WDT_ON);
|
||||
else
|
||||
a210_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, A210_AON_WDG_FUNC_AON_WDT_OFF);
|
||||
ret = a210_aon_call_rpc(ipc, &wdt_dev->msg, &ack_msg, true);
|
||||
if (ret){
|
||||
pr_err("%s: err:%d \n",__func__,ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void a210_pm_power_off(void)
|
||||
{
|
||||
struct a210_wdt_device *wdt_dev = a210_power_off_wdt;
|
||||
struct a210_aon_ipc *ipc = wdt_dev->ipc_handle;
|
||||
struct a210_aon_rpc_ack_common ack_msg = {0};
|
||||
int ret;
|
||||
|
||||
pr_info("[%s,%d]poweroff system...\n", __func__, __LINE__);
|
||||
|
||||
a210_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, A210_AON_WDG_FUNC_POWER_OFF);
|
||||
|
||||
ret = a210_aon_call_rpc(ipc, &wdt_dev->msg, &ack_msg, true);
|
||||
|
||||
if (ret)
|
||||
pr_err("failed to power off the system\n");
|
||||
}
|
||||
|
||||
|
||||
static DEVICE_ATTR(aon_sys_wdt, 0644, aon_sys_wdt_show, aon_sys_wdt_store);
|
||||
|
||||
static struct attribute *aon_sys_wdt_sysfs_entries[] = {
|
||||
&dev_attr_aon_sys_wdt.attr,
|
||||
NULL
|
||||
};
|
||||
static const struct attribute_group dev_attr_aon_sys_wdt_group = {
|
||||
.attrs = aon_sys_wdt_sysfs_entries,
|
||||
};
|
||||
|
||||
static int a210_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct a210_wdt_device *wdt_dev;
|
||||
int ret;
|
||||
struct watchdog_device *wdd;
|
||||
|
||||
printk("a210_wdt_probe\n");
|
||||
msleep(1000);
|
||||
wdt_dev = devm_kzalloc(dev, sizeof(*wdt_dev), GFP_KERNEL);
|
||||
if (!wdt_dev)
|
||||
return -ENOMEM;
|
||||
wdt_dev->is_aon_wdt_ena = 0;
|
||||
|
||||
ret = a210_aon_get_handle(&(wdt_dev->ipc_handle),"aon0");
|
||||
printk("a210_wdt_probe wdt_dev->ipc_handle 0x%x",wdt_dev->ipc_handle);
|
||||
printk("a210_wdt_probe ret %d",ret);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
return ret;
|
||||
printk("a210_wdt_probe get_handleOK %d",ret);
|
||||
wdd = devm_kzalloc(dev, sizeof(*wdd), GFP_KERNEL);
|
||||
if (!wdd)
|
||||
return -ENOMEM;
|
||||
|
||||
wdd->info = &a210_watchdog_info;
|
||||
wdd->ops = &a210_watchdog_ops;
|
||||
wdd->min_timeout = A210_WDT_MIN_TIMEOUT;
|
||||
wdd->max_timeout = A210_WDT_MAX_TIMEOUT;
|
||||
wdd->min_hw_heartbeat_ms = A210_RESET_PROTECTION_MS;
|
||||
wdd->status = WATCHDOG_NOWAYOUT_INIT_STATUS;
|
||||
|
||||
watchdog_set_restart_priority(wdd, 128);
|
||||
watchdog_set_drvdata(wdd, wdt_dev);
|
||||
|
||||
/* Set default timeout, maybe default value if the watchdog is running */
|
||||
wdd->timeout = A210_WDT_TIMEOUT;
|
||||
watchdog_init_timeout(wdd, 0, dev);
|
||||
a210_wdt_set_timeout(wdd, wdd->timeout);
|
||||
|
||||
platform_set_drvdata(pdev, wdt_dev);
|
||||
ret = a210_wdt_is_running(wdt_dev);
|
||||
if (ret < 0) {
|
||||
printk("a210_wdt_probe failed to get pmic wdt running state\n");
|
||||
pr_err("failed to get pmic wdt running state\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
a210_wdt_update_timeout(wdt_dev, wdd->timeout);
|
||||
set_bit(WDOG_HW_RUNNING, &wdd->status);
|
||||
}
|
||||
|
||||
ret = devm_watchdog_register_device(dev, wdd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
printk("[%s,%d] register power off callback\n", __func__, __LINE__);
|
||||
pr_info("[%s,%d] register power off callback\n", __func__, __LINE__);
|
||||
|
||||
pm_power_off = a210_pm_power_off;
|
||||
a210_power_off_wdt = wdt_dev;
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &dev_attr_aon_sys_wdt_group);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to create aon_sys_wdt sysfs.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_info("succeed to register p100 pmic watchdog\n");
|
||||
printk("a210_wdt_probe succeed to register p100 pmic watchdog\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a210_wdt_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct a210_wdt_device *wdt_dev = platform_get_drvdata(pdev);
|
||||
struct a210_aon_ipc *ipc = wdt_dev->ipc_handle;
|
||||
struct a210_aon_rpc_ack_common ack_msg = {0};
|
||||
int ret;
|
||||
|
||||
a210_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, A210_AON_WDG_FUNC_STOP);
|
||||
|
||||
ret = a210_aon_call_rpc(ipc, &wdt_dev->msg, &ack_msg, true);
|
||||
if (ret)
|
||||
dev_err(dev, "a210_wdt_suspend call aon wdt stop fail, ret:%d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a210_wdt_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct a210_wdt_device *wdt_dev = platform_get_drvdata(pdev);
|
||||
struct a210_aon_ipc *ipc = wdt_dev->ipc_handle;
|
||||
struct a210_aon_rpc_ack_common ack_msg = {0};
|
||||
int ret;
|
||||
|
||||
a210_wdt_msg_hdr_fill(&wdt_dev->msg.hdr, A210_AON_WDG_FUNC_START);
|
||||
|
||||
ret = a210_aon_call_rpc(ipc, &wdt_dev->msg, &ack_msg, true);
|
||||
if (ret)
|
||||
dev_err(dev, "a210_wdt_resume call aon wdt start fail, ret:%d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(a210_wdt_pm_ops, a210_wdt_suspend, a210_wdt_resume);
|
||||
|
||||
static struct platform_driver a210_wdt_driver = {
|
||||
.driver = {
|
||||
.name = DRV_NAME,
|
||||
.pm = pm_sleep_ptr(&a210_wdt_pm_ops),
|
||||
},
|
||||
.probe = a210_wdt_probe,
|
||||
};
|
||||
|
||||
static int __init a210_wdt_init(void)
|
||||
{
|
||||
static struct platform_device *pdev;
|
||||
int ret;
|
||||
|
||||
pdev = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
|
||||
if (IS_ERR(pdev))
|
||||
return PTR_ERR(pdev);
|
||||
|
||||
ret = platform_driver_register(&a210_wdt_driver);
|
||||
if (ret) {
|
||||
platform_device_unregister(pdev);
|
||||
return PTR_ERR(pdev);
|
||||
}
|
||||
|
||||
pr_info("Watchdog module: %s loaded\n", DRV_NAME);
|
||||
printk("Watchdog module: %s loaded\n", DRV_NAME);
|
||||
return 0;
|
||||
}
|
||||
device_initcall(a210_wdt_init);
|
||||
|
||||
MODULE_AUTHOR("Wei.Liu <lw312886@linux.alibaba.com>");
|
||||
MODULE_DESCRIPTION("PMIC Watchdog Driver for p100");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -10,76 +10,76 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
#define AON_RPC_MSG_MAGIC (0xef)
|
||||
#define P100_AON_RPC_VERSION (2)
|
||||
#define P100_AON_RPC_MSG_NUM (7)
|
||||
#define A210_AON_RPC_VERSION (2)
|
||||
#define A210_AON_RPC_MSG_NUM (7)
|
||||
|
||||
struct p100_aon_ipc;
|
||||
struct a210_aon_ipc;
|
||||
|
||||
enum p100_aon_rpc_svc {
|
||||
P100_AON_RPC_SVC_UNKNOWN = 0,
|
||||
P100_AON_RPC_SVC_PM = 1,
|
||||
P100_AON_RPC_SVC_MISC = 2,
|
||||
P100_AON_RPC_SVC_AVFS = 3,
|
||||
P100_AON_RPC_SVC_SYS = 4,
|
||||
P100_AON_RPC_SVC_WDG = 5,
|
||||
P100_AON_RPC_SVC_LPM = 6,
|
||||
P100_AON_RPC_SVC_MAX = 0x3F,
|
||||
enum a210_aon_rpc_svc {
|
||||
A210_AON_RPC_SVC_UNKNOWN = 0,
|
||||
A210_AON_RPC_SVC_PM = 1,
|
||||
A210_AON_RPC_SVC_MISC = 2,
|
||||
A210_AON_RPC_SVC_AVFS = 3,
|
||||
A210_AON_RPC_SVC_SYS = 4,
|
||||
A210_AON_RPC_SVC_WDG = 5,
|
||||
A210_AON_RPC_SVC_LPM = 6,
|
||||
A210_AON_RPC_SVC_MAX = 0x3F,
|
||||
};
|
||||
|
||||
enum p100_aon_misc_func {
|
||||
P100_AON_MISC_FUNC_UNKNOWN = 0,
|
||||
P100_AON_MISC_FUNC_SET_CONTROL = 1,
|
||||
P100_AON_MISC_FUNC_GET_CONTROL = 2,
|
||||
P100_AON_MISC_FUNC_REGDUMP_CFG = 3,
|
||||
enum a210_aon_misc_func {
|
||||
A210_AON_MISC_FUNC_UNKNOWN = 0,
|
||||
A210_AON_MISC_FUNC_SET_CONTROL = 1,
|
||||
A210_AON_MISC_FUNC_GET_CONTROL = 2,
|
||||
A210_AON_MISC_FUNC_REGDUMP_CFG = 3,
|
||||
};
|
||||
|
||||
enum p100_aon_wdg_func {
|
||||
P100_AON_WDG_FUNC_UNKNOWN = 0,
|
||||
P100_AON_WDG_FUNC_START = 1,
|
||||
P100_AON_WDG_FUNC_STOP = 2,
|
||||
P100_AON_WDG_FUNC_PING = 3,
|
||||
P100_AON_WDG_FUNC_TIMEOUTSET = 4,
|
||||
P100_AON_WDG_FUNC_RESTART = 5,
|
||||
P100_AON_WDG_FUNC_GET_STATE = 6,
|
||||
P100_AON_WDG_FUNC_POWER_OFF = 7,
|
||||
P100_AON_WDG_FUNC_AON_WDT_ON = 8,
|
||||
P100_AON_WDG_FUNC_AON_WDT_OFF = 9,
|
||||
enum a210_aon_wdg_func {
|
||||
A210_AON_WDG_FUNC_UNKNOWN = 0,
|
||||
A210_AON_WDG_FUNC_START = 1,
|
||||
A210_AON_WDG_FUNC_STOP = 2,
|
||||
A210_AON_WDG_FUNC_PING = 3,
|
||||
A210_AON_WDG_FUNC_TIMEOUTSET = 4,
|
||||
A210_AON_WDG_FUNC_RESTART = 5,
|
||||
A210_AON_WDG_FUNC_GET_STATE = 6,
|
||||
A210_AON_WDG_FUNC_POWER_OFF = 7,
|
||||
A210_AON_WDG_FUNC_AON_WDT_ON = 8,
|
||||
A210_AON_WDG_FUNC_AON_WDT_OFF = 9,
|
||||
};
|
||||
|
||||
enum p100_aon_sys_func {
|
||||
P100_AON_SYS_FUNC_UNKNOWN = 0,
|
||||
P100_AON_SYS_FUNC_AON_RESERVE_MEM = 1,
|
||||
enum a210_aon_sys_func {
|
||||
A210_AON_SYS_FUNC_UNKNOWN = 0,
|
||||
A210_AON_SYS_FUNC_AON_RESERVE_MEM = 1,
|
||||
};
|
||||
|
||||
enum p100_aon_lpm_func {
|
||||
P100_AON_LPM_FUNC_UNKNOWN = 0,
|
||||
P100_AON_LPM_FUNC_REQUIRE_STR = 1,
|
||||
P100_AON_LPM_FUNC_RESUME_STR = 2,
|
||||
P100_AON_LPM_FUNC_REQUIRE_STD = 3,
|
||||
P100_AON_LPM_FUNC_CPUHP = 4,
|
||||
P100_AON_LPM_FUNC_REGDUMP_CFG = 5,
|
||||
enum a210_aon_lpm_func {
|
||||
A210_AON_LPM_FUNC_UNKNOWN = 0,
|
||||
A210_AON_LPM_FUNC_REQUIRE_STR = 1,
|
||||
A210_AON_LPM_FUNC_RESUME_STR = 2,
|
||||
A210_AON_LPM_FUNC_REQUIRE_STD = 3,
|
||||
A210_AON_LPM_FUNC_CPUHP = 4,
|
||||
A210_AON_LPM_FUNC_REGDUMP_CFG = 5,
|
||||
};
|
||||
|
||||
enum p100_aon_pm_func {
|
||||
P100_AON_PM_FUNC_UNKNOWN = 0,
|
||||
P100_AON_PM_FUNC_SET_RESOURCE_REGULATOR = 1,
|
||||
P100_AON_PM_FUNC_GET_RESOURCE_REGULATOR = 2,
|
||||
P100_AON_PM_FUNC_SET_RESOURCE_POWER_MODE = 3,
|
||||
P100_AON_PM_FUNC_PWR_SET = 4,
|
||||
P100_AON_PM_FUNC_PWR_GET = 5,
|
||||
P100_AON_PM_FUNC_CHECK_FAULT = 6,
|
||||
P100_AON_PM_FUNC_GET_TEMPERATURE = 7,
|
||||
enum a210_aon_pm_func {
|
||||
A210_AON_PM_FUNC_UNKNOWN = 0,
|
||||
A210_AON_PM_FUNC_SET_RESOURCE_REGULATOR = 1,
|
||||
A210_AON_PM_FUNC_GET_RESOURCE_REGULATOR = 2,
|
||||
A210_AON_PM_FUNC_SET_RESOURCE_POWER_MODE = 3,
|
||||
A210_AON_PM_FUNC_PWR_SET = 4,
|
||||
A210_AON_PM_FUNC_PWR_GET = 5,
|
||||
A210_AON_PM_FUNC_CHECK_FAULT = 6,
|
||||
A210_AON_PM_FUNC_GET_TEMPERATURE = 7,
|
||||
};
|
||||
|
||||
struct p100_aon_rpc_msg_hdr {
|
||||
struct a210_aon_rpc_msg_hdr {
|
||||
uint8_t ver; ///< version of msg hdr
|
||||
uint8_t size; ///< msg size ,uinit in bytes,the size includes rpc msg header self.
|
||||
uint8_t svc; ///< rpc main service id
|
||||
uint8_t func; ///< rpc sub func id of specific service, sent by caller
|
||||
} __packed __aligned(1);
|
||||
|
||||
struct p100_aon_rpc_ack_common {
|
||||
struct p100_aon_rpc_msg_hdr hdr;
|
||||
struct a210_aon_rpc_ack_common {
|
||||
struct a210_aon_rpc_msg_hdr hdr;
|
||||
uint8_t err_code;
|
||||
} __packed __aligned(1);
|
||||
|
||||
@@ -158,13 +158,13 @@ struct p100_aon_rpc_ack_common {
|
||||
/*
|
||||
* Defines for SC PM Power Mode
|
||||
*/
|
||||
#define P100_AON_PM_PW_MODE_OFF 0 /* Power off */
|
||||
#define P100_AON_PM_PW_MODE_STBY 1 /* Power in standby */
|
||||
#define P100_AON_PM_PW_MODE_LP 2 /* Power in low-power */
|
||||
#define P100_AON_PM_PW_MODE_ON 3 /* Power on */
|
||||
#define A210_AON_PM_PW_MODE_OFF 0 /* Power off */
|
||||
#define A210_AON_PM_PW_MODE_STBY 1 /* Power in standby */
|
||||
#define A210_AON_PM_PW_MODE_LP 2 /* Power in low-power */
|
||||
#define A210_AON_PM_PW_MODE_ON 3 /* Power on */
|
||||
|
||||
int p100_aon_call_rpc(struct p100_aon_ipc *ipc, void *msg, void *ack_msg, bool have_resp);
|
||||
int p100_aon_get_handle(struct p100_aon_ipc **ipc, char* name);
|
||||
int p100_aon_misc_set_control(struct p100_aon_ipc *ipc, u16 resource, u32 ctrl, u32 val);
|
||||
int p100_aon_misc_get_control(struct p100_aon_ipc *ipc, u16 resource, u32 ctrl, u32 *val);
|
||||
int a210_aon_call_rpc(struct a210_aon_ipc *ipc, void *msg, void *ack_msg, bool have_resp);
|
||||
int a210_aon_get_handle(struct a210_aon_ipc **ipc, char* name);
|
||||
int a210_aon_misc_set_control(struct a210_aon_ipc *ipc, u16 resource, u32 ctrl, u32 val);
|
||||
int a210_aon_misc_get_control(struct a210_aon_ipc *ipc, u16 resource, u32 ctrl, u32 *val);
|
||||
#endif /* _SC_IPC_H */
|
||||
|
||||
@@ -19,7 +19,7 @@ _DEFAULT_OUTPUT = 'compile_commands.json'
|
||||
_DEFAULT_LOG_LEVEL = 'WARNING'
|
||||
|
||||
_FILENAME_PATTERN = r'^\..*\.cmd$'
|
||||
_LINE_PATTERN = r'^savedcmd_[^ ]*\.o := (.* )([^ ]*\.[cS]) *(;|$)'
|
||||
_LINE_PATTERN = r'^(saved)?cmd_[^ ]*\.o := (?P<command_prefix>.* )(?P<file_path>[^ ]*\.[cS]) *(;|$)'
|
||||
_VALID_LOG_LEVELS = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL']
|
||||
# The tools/ directory adopts a different build system, and produces .cmd
|
||||
# files in a different format. Do not support it.
|
||||
@@ -64,7 +64,7 @@ def parse_arguments():
|
||||
args = parser.parse_args()
|
||||
|
||||
return (args.log_level,
|
||||
os.path.abspath(args.directory),
|
||||
os.path.realpath(args.directory),
|
||||
args.output,
|
||||
args.ar,
|
||||
args.paths if len(args.paths) > 0 else [args.directory])
|
||||
@@ -167,13 +167,13 @@ def process_line(root_directory, command_prefix, file_path):
|
||||
root_directory or file_directory.
|
||||
"""
|
||||
# The .cmd files are intended to be included directly by Make, so they
|
||||
# escape the pound sign '#', either as '\#' or '$(pound)' (depending on the
|
||||
# kernel version). The compile_commands.json file is not interepreted
|
||||
# by Make, so this code replaces the escaped version with '#'.
|
||||
prefix = command_prefix.replace('\#', '#').replace('$(pound)', '#')
|
||||
# escape the pound sign '#' as '$(pound)'. The compile_commands.json file
|
||||
# is not interepreted by Make, so this code replaces the escaped version
|
||||
# with '#'.
|
||||
prefix = command_prefix.replace('$(pound)', '#')
|
||||
|
||||
# Use os.path.abspath() to normalize the path resolving '.' and '..' .
|
||||
abs_path = os.path.abspath(os.path.join(root_directory, file_path))
|
||||
# Return the canonical path, eliminating any symbolic links encountered in the path.
|
||||
abs_path = os.path.realpath(os.path.join(root_directory, file_path))
|
||||
if not os.path.exists(abs_path):
|
||||
raise ValueError('File %s not found' % abs_path)
|
||||
return {
|
||||
@@ -213,15 +213,15 @@ def main():
|
||||
result = line_matcher.match(f.readline())
|
||||
if result:
|
||||
try:
|
||||
entry = process_line(directory, result.group(1),
|
||||
result.group(2))
|
||||
entry = process_line(directory, result.group('command_prefix'),
|
||||
result.group('file_path'))
|
||||
compile_commands.append(entry)
|
||||
except ValueError as err:
|
||||
logging.info('Could not add line from %s: %s',
|
||||
cmdfile, err)
|
||||
|
||||
with open(output, 'wt') as f:
|
||||
json.dump(compile_commands, f, indent=2, sort_keys=True)
|
||||
json.dump(sorted(compile_commands, key=lambda x: x["file"]), f, indent=2, sort_keys=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -136,7 +136,7 @@ static void es8156_enable_spk(struct es8156_priv *es8156, bool enable)
|
||||
static const char *es8156_DAC_SRC[] = { "Left to Left, Right to Right",
|
||||
"Right to both Left and Right","Left to both Left & Right", "Left to Right, Right to Left" };
|
||||
|
||||
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9600, 50, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -9550, 50, 1);
|
||||
static const DECLARE_TLV_DB_SCALE(alc_gain_tlv,-2800,400,1);
|
||||
static SOC_ENUM_SINGLE_DECL(es8165_dac_enum, ES8156_MISC_CONTROL3_REG18, 4, es8156_DAC_SRC);
|
||||
|
||||
@@ -152,8 +152,8 @@ static const struct snd_kcontrol_new es8156_snd_controls[] = {
|
||||
SOC_DOUBLE("ALC Maximum Minimum Volume",ES8156_ALC_CONFIG3_REG17,
|
||||
4,0,15,0),
|
||||
/* DAC Digital controls */
|
||||
SOC_SINGLE_TLV("DAC Playback Volume", ES8156_VOLUME_CONTROL_REG14,
|
||||
0, ES8156_VOL_MAX, 0, dac_vol_tlv),
|
||||
SOC_SINGLE_TLV("Master Playback Volume", ES8156_VOLUME_CONTROL_REG14, 0,
|
||||
ES8156_VOL_MAX, 0, dac_vol_tlv),
|
||||
SOC_SINGLE("HP Switch",ES8156_ANALOG_SYS3_REG22,3,1,0),
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user