Drivers/IPU: add IPU driver for hikey970

Add IPU device driver and device tree source for HiKey970.

Signed-off-by: zwx305167 <zwx305167@notesmail.huawei.com>
This commit is contained in:
zwx305167
2018-03-07 14:12:31 +08:00
committed by Guodong Xu
parent d02cfc90a2
commit cf21836d0d
21 changed files with 6156 additions and 2 deletions
+2
View File
@@ -18,6 +18,8 @@
#include "kirin970_ipc.dtsi"
#include "kirin970-coresight.dtsi"
#include "kirin970-drm.dtsi"
#include "kirin970_ics_cs.dtsi"
/ {
model = "HiKey970";
compatible = "Hisilicon,kirin970-hikey970", "Hisilicon,kirin970";
@@ -0,0 +1,141 @@
/*
* Hisilicon Ltd. Kirin970 SoC
*
* Copyright (C) 2014- Hisilicon Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* publishhed by the Free Software Foundation.
*/
/ {
cambricon-ipu@ff400000{
// vipu-supply = <&ics>;
compatible = "hisilicon,cambricon-ipu";
reg = <0x0 0xff400000 0x0 0x100000>,<0x0 0xff500000 0x0 0x100000>;
interrupts = <0 293 4>;
interrupt-names = "ipu_dma_irq";
ics-platform = "kirin970_cs";
// clocks = <&clk_gate_ics>;
clocks = <&media2_crg KIRIN970_CLK_GATE_ICSFREQ>;
clock-names = "clk-ics";
status = "ok"
ipu-and-vcodecbus-clock-rate {
start-rate = <900000000>;
stop-rate = <332000000>;
ipu-low = <384000000>;
ipu-middle = <600000000>;
ipu-high = <900000000>;
ipu-low-temperature = <600000000>;
vcodecbus-low = <185000000>;
vcodecbus-middle = <332000000>;
vcodecbus-high = <450000000>;
vcodecbus-default = <415000000>;
vcodecbus-high2default = <225000000>;
};
iommu_info {
start-addr = <0x40000>;
iova-align = <0x1000>;
size = <0x80000000>;
};
smmu_master {
smmu-mstr-base-addr = <0xff4a0000>;
smmu-mstr-glb-bypass = <0x0000>;
smmu-mstr-end-ack = <0x001c>;
smmu-mstr-smrx-start = <0x0028>;
smmu-mstr-inpt-sel = <0x0034>;
smmu-mstr-intmask = <0x0040>;
smmu-mstr-intstat = <0x0048>;
smmu-mstr-intclr = <0x004c>;
smmu-mstr-dbg-port-in-0 = <0x0070>;
smmu-mstr-dbg-port-out = <0x0078>;
smmu-mstr-smrx-0-stream-0 = <0x0100>;
smmu-mstr-smrx-0-stream-1 = <0x0104>;
smmu-mstr-smrx-0-stream-2 = <0x0108>;
smmu-mstr-smrx-0-stream-3 = <0x010c>;
read-cmd-total-cnt-stream-0 = <0x0600>;
read-cmd-total-cnt-stream-1 = <0x0604>;
read-cmd-total-cnt-stream-2 = <0x0608>;
read-cmd-miss-cnt-stream-0 = <0x0760>;
read-cmd-miss-cnt-stream-1 = <0x0764>;
read-cmd-miss-cnt-stream-2 = <0x0768>;
read-data-total-cnt-stream-0 = <0x08c0>;
read-data-total-cnt-stream-1 = <0x08c4>;
read-data-total-cnt-stream-2 = <0x08c8>;
read-cmd-case-cnt-stream-0 = <0x0a20>;
read-cmd-case-cnt-stream-1 = <0x0a24>;
read-cmd-case-cnt-stream-2 = <0x0a28>;
read-cmd-case-cnt-stream-3 = <0x0a2c>;
read-cmd-case-cnt-stream-4 = <0x0a30>;
read-cmd-case-cnt-stream-5 = <0x0a34>;
read-cmd-trans-latency = <0x0a38>;
write-cmd-total-cnt = <0x0b00>;
write-cmd-miss-cnt = <0x0c60>;
write-data-total-cnt = <0x0dc0>;
write-cmd-case-cnt-stream-0 = <0x0f20>;
write-cmd-case-cnt-stream-1 = <0x0f24>;
write-cmd-case-cnt-stream-2 = <0x0f28>;
write-cmd-case-cnt-stream-3 = <0x0f2c>;
write-cmd-case-cnt-stream-4 = <0x0f30>;
write-cmd-case-cnt-stream-5 = <0x0f34>;
write-cmd-trans-latency = <0x0f38>;
};
smmu_common {
smmu-common-base-addr = <0xff480000>;
smmu-scr = <0x0000>;
smmu-intmask-ns = <0x0010>;
smmu-intstat-ns = <0x0018>;
smmu-intclr-ns = <0x001c>;
smmu-cb-ttbr0 = <0x0204>;
smmu-cb-ttbcr = <0x020c>;
smmu-scachei-all = <0x0214>;
smmu-fama-ctrl1-ns = <0x0224>;
smmu-addr-msb = <0x0300>;
smmu-err-rdaddr = <0x0304>;
smmu-err-wraddr = <0x0308>;
smmu-opref-addr = <0x03a4>;
smmu-opref-ctrl = <0x03a8>;
};
ics_irq {
ics-irq-base-addr = <0xff4a2000>;
ics-irq-mask-ns = <0x0000>;
ics-irq-status-ns = <0x0008>;
ics-irq-clr-ns = <0x000c>;
};
ics_noc_bus {
base-addr = <0xe8950000>;
qos-type = <0x000c>;
factor = <0x0010>;
saturation = <0x0014>;
qos_extcontrol = <0x0018>;
};
pmctrl {
base-addr = <0xfff31000>;
noc-power-idle-req = <0x0380>;
noc-power-idle-ack = <0x0384>;
noc-power-idle-stat = <0x0388>;
};
pctrl {
base-addr = <0xe8a09000>;
peri-stat3 = <0x00a0>;
};
media2 {
base-addr = <0xe8900000>;
peren0 = <0x000>;
perdis0 = <0x004>;
perclken0 = <0x008>;
perstat0 = <0x00c>;
perrsten0 = <0x030>;
perrstdis0 = <0x034>;
perrststat0 = <0x038>;
};
peri {
base-addr = <0xfff35000>;
clkdiv8 = <0xc8>;
clkdiv18 = <0xf0>;
perpwrstat = <0x158>;
perpwrack = <0x15c>;
peristat7 = <0x50c>;
};
};
};
+1
View File
@@ -260,6 +260,7 @@ CONFIG_VIRTIO_BLK=y
CONFIG_SRAM=y
CONFIG_UID_SYS_STATS=y
CONFIG_HISI_HIKEY_USB=y
CONFIG_HISI_ICS_IPU=y
CONFIG_MEMORY_STATE_TIME=y
CONFIG_TI_ST=y
CONFIG_ST_HCI=y
+1
View File
@@ -561,6 +561,7 @@ static const struct hisi_divider_clock kirin970_media1_divider_clks[] = {
static const struct hisi_gate_clock kirin970_media2_gate_sep_clks[] = {
{ KIRIN970_CLK_GATE_VDECFREQ, "clk_gate_vdecfreq", "clk_div_vdec", CLK_SET_RATE_PARENT, 0x00, 8, 0, },
{ KIRIN970_CLK_GATE_VENCFREQ, "clk_gate_vencfreq", "clk_div_venc", CLK_SET_RATE_PARENT, 0x00, 5, 0, },
{ KIRIN970_CLK_GATE_ICSFREQ, "clk_gate_icsfreq", "clk_div_ics", CLK_SET_RATE_PARENT, 0x00, 2, 0, },
};
static void kirin970_clk_crgctrl_init(struct device_node *np)
+1
View File
@@ -11,6 +11,7 @@ if HISILICON_PLATFORM
source "drivers/hisi/mailbox/Kconfig"
source "drivers/hisi/hifi_dsp/Kconfig"
source "drivers/hisi/hifi_mailbox/Kconfig"
source "drivers/hisi/ics/Kconfig"
endif #HISILICON_PLATFORM
+1 -1
View File
@@ -1,4 +1,4 @@
obj-$(CONFIG_HISILICON_PLATFORM_MAILBOX) += mailbox/
obj-$(CONFIG_HIFI_DSP_ONE_TRACK) += hifi_dsp/
obj-$(CONFIG_HIFI_MAILBOX) += hifi_mailbox/
obj-$(CONFIG_HISI_ICS_IPU) += ics/
+40
View File
@@ -0,0 +1,40 @@
#
# Cambricon IPU Platform Specific Drivers
#
menuconfig HISI_ICS_IPU_PLATFORM
bool "Platform supoort for Cambricon IPU Device"
default y
help
Say Y here to get to see options for device drivers of various
Cambricon IPU platforms. This option itself does not add any kernel code.
If you say N, all options in this submenu will be skipped and disabled.
if HISI_ICS_IPU_PLATFORM
config HISI_ICS_IPU
tristate "Cambricon IPU Driver"
default y
help
Cambricon IPU Platform driver.
config HISI_IPU_SET_VCODECBUS
tristate "Allow IPU Driver to set VCODEC bus clock rate"
default n
help
Allow IPU Driver to set VCODEC bus clock rate.
config HISI_IPU_MNTN
tristate "Enable IPU Driver maintain function"
default n
help
Enable IPU Driver maintain function.
config HISI_IPU_REGULATOR
tristate "Enable IPU Driver regulator control"
default n
help
Enable IPU Driver regulator control.
endif # HISI_ICS_IPU_PLATFORM
+14
View File
@@ -0,0 +1,14 @@
ifeq ($(es_low_freq),true)
EXTRA_CFLAGS += -DCONFIG_ES_VDEC_LOW_FREQ
endif
obj-$(CONFIG_HISI_ICS_IPU) += cambricon_ipu.o
obj-$(CONFIG_HISI_ICS_IPU) += ipu_smmu_drv.o
obj-$(CONFIG_HISI_ICS_IPU) += ipu_clock.o
obj-$(CONFIG_HISI_IPU_MNTN) += ipu_mntn.o
ifneq ($(TARGET_BUILD_VARIANT),user)
obj-$(CONFIG_HISI_ICS_IPU) += ics_debug_proxy.o
obj-y += ics_debug.o
endif
EXTRA_CFLAGS += -I$(srctree)/drivers/hisi/ap/platform/kirin970
File diff suppressed because it is too large Load Diff
+251
View File
@@ -0,0 +1,251 @@
/*
* Generic driver head file for the cambricon ipu device.
*
* Copyright (C) 2016 Cambricon Limited
*
* Licensed under the GPL v2 or later.
*/
#ifndef _CAMBRICON_IPU_H
#define _CAMBRICON_IPU_H
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/timer.h>
#include <linux/kthread.h>
#include "ipu_smmu_drv.h"
#include "ipu_clock.h"
struct irq_reg_offset {
unsigned int ics_irq_base_addr;
unsigned int ics_irq_mask_ns;
unsigned int ics_irq_clr_ns;
};
struct ics_noc_bus_reg_offset {
unsigned int base_addr;
unsigned int qos_type;
unsigned int factor;
unsigned int saturation;
unsigned int qos_extcontrol;
};
struct pmctrl_reg_offset {
unsigned int base_addr;
unsigned int noc_power_idle_req;
unsigned int noc_power_idle_ack;
unsigned int noc_power_idle_stat;
};
struct pctrl_reg_offset {
unsigned int base_addr;
unsigned int peri_stat3;
};
struct media2_reg_offset {
unsigned int base_addr;
unsigned int peren0;
unsigned int perdis0;
unsigned int perclken0;
unsigned int perstat0;
unsigned int perrsten0;
unsigned int perrstdis0;
unsigned int perrststat0;
};
struct peri_reg_offset {
unsigned int base_addr;
unsigned int clkdiv8;
unsigned int clkdiv18;
unsigned int perpwrstat;
unsigned int perpwrack;
unsigned int peristat7;
};
enum ipu_reset_trategy {
IPU_RESET_UNSUPPORT = 0,
IPU_RESET_BY_CONFIG_NOC_BUS,
IPU_SOFT_RESET,
};
enum ipu_bandwidth_lmt_trategy {
IPU_BANDWIDTH_LMT_UNSUPPORT = 0,
IPU_BANDWIDTH_LMT_BY_QOS,
IPU_BANDWIDTH_LMT_BY_RW_OSD,
};
struct ics_feature_tree {
bool finish_irq_expand_ns;
bool finish_irq_expand_p;
bool finish_irq_expand_s;
bool finish_irq_to_hifi;
bool finish_irq_to_ivp;
bool finish_irq_to_isp;
bool finish_irq_to_lpm3;
bool finish_irq_to_iocmu;
bool smmu_port_select;
bool level1_irq;
bool performance_monitor;
bool wr_qword;
bool soft_watchdog_enable;
bool lpm3_set_vcodecbus;
bool smmu_mstr_hardware_start;
unsigned int ipu_reset_when_in_error;
unsigned int ipu_bandwidth_lmt;
};
typedef int Priority;
/* the ipu task type */
typedef enum taskType {
IPU_TASK_ENUM_START = 0,
IPU_NONE_TASK = IPU_TASK_ENUM_START,
/*First*/
IPU_COMPUTE_TASK,
IPU_SYNC_TASK,
//Add new to here!
IPU_TASK_ENUM_END
} taskType_t;
typedef enum taskFlag{
IPU_TASK_FLAG_START = 0,
IPU_TASK_FLAG_NONE = IPU_TASK_FLAG_START,
/*First*/
IPU_TASK_FLAG_SYNC_WAITING,
IPU_TASK_FLAG_SYNC_DONE,
//Add new to here!
IPU_TASK_FLAG_END
} taskFlag_t;
struct ipu_wtd {
bool enable;
int status;
struct mutex timer_mutex;
struct timer_list timer;
struct task_struct *task;
struct semaphore sem;
};
/* the ipu task element */
typedef struct taskStruct {
taskType_t taskType;//define different cmd type
taskFlag_t* ptaskFlag;//use to mark task status
unsigned long offchipInstAddr;
unsigned long taskId;
Priority prior;
} taskElement;
#define BOOT_INST_SIZE (64)
#define BOOT_INST_NUMBER (4)
/* this struct stores the temp data of boot instrument for IPU initialization after power-up */
struct boot_inst_set {
/* mutex */
struct mutex boot_mutex;
/* store the value from IOCTL WRITE when IPU is off */
unsigned int ipu_access_ddr_addr;
/* boot-instrument data */
unsigned char boot_inst[BOOT_INST_SIZE * BOOT_INST_NUMBER];
/* size of boot-inst data */
unsigned int boot_inst_size;
/* bool flag to record whether access_ddr_addr is recorded */
bool access_ddr_addr_is_config;
/* bool flag to record whether boot_inst is recorded */
bool boot_inst_recorded_is_config;
};
/* cambricon ipu private data */
struct cambricon_ipu_private
{
const char *name;
unsigned int irq;
bool ipu_device_opened;
bool ipu_power_up;
struct mutex power_mutex;
struct mutex open_mutex;
struct mutex bandwidth_lmt_mutex;
struct boot_inst_set boot_inst_set;
struct smmu_statistic stat;
bool smmu_stat_en;
struct mutex stat_mutex;
/* config reg addr */
unsigned int config_reg_length;
phys_addr_t config_reg_phys_addr;
void __iomem *config_reg_virt_addr;
/* inst reg addr */
unsigned int inst_ram_size;
phys_addr_t inst_ram_phys_addr;
void __iomem *inst_ram_virt_addr;
/* ioremap addr */
void __iomem *ics_irq_io_addr;
void __iomem *noc_bus_io_addr;
void __iomem *pmctrl_io_addr;
void __iomem *pctrl_io_addr;
void __iomem *media2_io_addr;
void __iomem *peri_io_addr;
struct semaphore config_reg_sem;
struct semaphore inst_ram_sem;
struct semaphore llseek_sem;
struct semaphore task_fifo_sem;
/* char device */
struct cdev cdev; /* ipu char device */
/* platform device resource */
struct resource *inst_mem, *cfg_mem;
struct regulator *vipu_ip;
/* clock */
struct ics_clock clk;
struct mutex reset_mutex;
unsigned long reset_va;
unsigned long smmu_ttbr0;
void *smmu_rw_err_phy_addr;
struct irq_reg_offset irq_reg_offset;
struct ics_noc_bus_reg_offset ics_noc_bus_reg_offset;
struct pmctrl_reg_offset pmctrl_reg_offset;
struct pctrl_reg_offset pctrl_reg_offset;
struct media2_reg_offset media2_reg_offset;
struct peri_reg_offset peri_reg_offset;
struct ics_feature_tree feature_tree;
struct ipu_wtd reset_wtd;
unsigned long computed_task_cnt;
};
#define IOREAD_RANGE(base, size) \
do { \
unsigned long i; \
DEBUG("IOREAD_RANGE(%p, %u)", (void*)(base), (u32)(size)); \
for (i = 0; i < (size); i += 4) { \
unsigned long addr = (unsigned long)(base) + i; \
u32 val = ioread32((void*)addr); \
if (val != 0) { \
DEBUG("*(u32*)(%s + %lx): %x", #base, i, val); \
} \
} \
} while (0)
#define READ_IPU_VERSION_REGISTER() \
do { \
u32 version = ioread32((void*)((unsigned long)adapter->config_reg_virt_addr + IPU_VERSION_REG)); \
DEBUG("IPU_VERSION: %x", version); \
} while (0)
#endif
+803
View File
@@ -0,0 +1,803 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/sysfs.h>
#include "ics_debug.h"
#define CLASS_NAME "ics_debug"
#define UNMASK_LPM3 (0)
#define UNMASK_IOMCU (1)
#define UNMASK_ISP (2)
#define UNMASK_IVP (3)
#define UNMASK_HIFI (4)
#define PERI_OFFSET_PEREN0 (0x000)
#define PERI_OFFSET_PERDIS0 (0x004)
#define PERI_OFFSET_PEREN6 (0x410)
#define PERI_OFFSET_PERDIS6 (0x414)
#define PERI_OFFSET_PERRSTEN4 (0x090)
#define PERI_OFFSET_PERRSTDIS4 (0x094)
#define PERI_OFFSET_CLKDIV18 (0x0F0)
#define PERI_OFFSET_PERPWREN (0x150)
#define PERI_OFFSET_PERPWRDIS (0x154)
#define PERI_OFFSET_ISOEN (0x144)
#define PERI_OFFSET_ISODIS (0x148)
#define PERI_OFFSET_CLKDIV5 (0x0bc)
#define PERI_OFFSET_CLKDIV8 (0x0c8)
#define PERI_OFFSET_CLKDIV15 (0x0e4)
#define PERI_ISOEN_ICS_ISO_EN (0x00000100)
#define PERI_ISODIS_ICS_ISO_UN (0x00000100)
#define PERI_CLKDIV8_SEL_ICS_PLL2 (0xf0004000)
#define PERI_CLKDIV8_SEL_ICS_PLL0 (0xf0002000)
#define PERI_PERPWREN_ICSPWREN_EN (0x00000100)
#define PERI_PERPWRDIS_ICS_PWR_DIS (0x00000100)
#define PERI_PERRSTDIS4_IP_RST_MEDIA2 (0x00000001)
#define PERI_CLKDIV15_SEL_FREQ_DIV4_ICS (0x7e000600)
#define PERI_PERRSTEN4_IP_RST_MEDIA_CRG (0x00000002)
#define PERI_CLKDIV8_SEL_VCODECBUS_PLL2 (0x000f0004)
#define PERI_CLKDIV8_SEL_VCODECBUS_PLL0 (0x000f0002)
#define PERI_CLKDIV15_SEL_FREQ_DIV3_ICS (0x7e000400)
#define PERI_CLKDIV15_SEL_FREQ_DIV2_ICS (0x7e000200)
#define PERI_CLKDIV18_SC_GT_CLK_ICS__EN (0x40000000)
#define PERI_PERRSTEN4_IP_RST_MEDIA2_EN (0x00000001)
#define PERI_CLKDIV18_SC_GT_CLK_VCODEBUS_EN (0x01000000)
#define PERI_CLKDIV5_SET_FREQ_DIV4_VCODECBUS (0x003f0003)
#define PERI_CLKDIV5_SET_FREQ_DIV5_VCODECBUS (0x003f0004)
#define PERI_CLKDIV5_SET_FREQ_DIV8_VCODECBUS (0x003f0007)
#define PERI_PEREN0_GT_CLK_VCODECBUS2DDRC_EN (0x00000020)
#define PERI_PERRSTDIS4_IP_RST_MEDIA2_CRG_EN (0x00000002)
#define PERI_PERDIS0_GT_CLK_VCODECBUS2DDRC_UN (0x00000020)
#define PERI_CLKDIV18_SC_GT_CLK_ICS_OPEN_AND_EN (0x40004000)
#define PERI_CLKDIV18_SC_GT_CLK_VCODEBUS_OPEN_AND_EN (0x01000100)
#define PERI_PEREN6_GT_CLK_CFGBUS_MEDIA_AND_MEDIA2_EN (0x00010200)
#define PERI_PERDIS6_GT_CLK_CFGBUS_MEDIA_AND_MEDIA2_EN (0x00010200)
#define MEDIA2_OFFSET_PEREN0 (0x000)
#define MEDIA2_OFFSET_PERDIS0 (0x004)
#define MEDIA2_OFFSET_PERRSTEN0 (0x030)
#define MEDIA2_OFFSET_PERRSTDIS0 (0x034)
#define MEDIA2_PEREN0_GT_CLK_VCODEBUS_EN (0x00000200)
#define MEDIA2_PERDIS0_GT_CLK_VCODEBUS_UN (0x00000200)
#define MEDIA2_PEREN0_GT_CLK_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_EN (0x00000007)
#define MEDIA2_PERDIS0_GT_CLK_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_UN (0x00000007)
#define MEDIA2_PERRSTEN0_IP_RST_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_EN (0x00000038)
#define MEDIA2_PERRSTDIS0_IP_RST_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_UN (0x00000038)
#define PMCTRL_OFFSET_NOC_POWER_IDLEREQ_0 (0x380)
#define PMCTRL_OFFSET_NOC_POWER_IDLEACK_0 (0x384)
#define PMCTRL_OFFSET_NOC_POWER_IDLE_0 (0x388)
#define PMCTRL_NOC_POWER_IDLE_0_NOC_ICS_POWER_IDLE (0x200)
#define PMCTRL_NOC_POWER_IDLE_0_NOC_ICS_POWER_IDLE_UN (0x0)
#define PMCTRL_NOC_POWER_IDLE_0_NOC_ICS_POWER_IDLE_EN (0x200)
#define PMCTRL_NOC_POWER_IDLEACK_0_NOC_ICS_POWER_IDLEACK (0x200)
#define PMCTRL_NOC_POWER_IDLEACK_0_NOC_ICS_POWER_IDLEACK_UN (0x0)
#define PMCTRL_NOC_POWER_IDLEACK_0_NOC_ICS_POWER_IDLEACK_EN (0x200)
#define PMCTRL_NOC_POWER_IDLEACK_0_NOC_VCODEC_BUS_POWER_IDLEACK (0x10)
#define PMCTRL_NOC_POWER_IDLE_0_NOC_VCODEC_BUS_POWER_IDLE_STATUS (0x10)
#define PMCTRL_NOC_POWER_IDLEACK_0_NOC_VCODEC_BUS_POWER_IDLEACK_UN (0x0)
#define PMCTRL_NOC_POWER_IDLEREQ_0_NOC_ICS_POWER_IDLEREQ_EN (0x02000000)
#define PMCTRL_NOC_POWER_IDLEACK_0_NOC_VCODEC_BUS_POWER_IDLEACK_EN (0x10)
#define PMCTRL_NOC_POWER_IDLE_0_NOC_VCODEC_BUS_POWER_IDLE_STATUS_UN (0x0)
#define PMCTRL_NOC_POWER_IDLE_0_NOC_VCODEC_BUS_POWER_IDLE_STATUS_EN (0x10)
#define PMCTRL_NOC_POWER_IDLEREQ_0_NOC_ICS_POWER_IDLEREQ_REQ_AND_EN (0x02000200)
#define PMCTRL_NOC_NOC_POWER_IDLEREQ_0_NOC_VCODEC_BUS_POWER_IDLEREQ_EN (0x00100000)
#define PMCTRL_NOC_NOC_POWER_IDLEREQ_0_NOC_VCODEC_BUS_POWER_IDLEREQ_REQ_AND_EN (0x00100010)
#define CONFIG_REG_VIRT_ADDR_OFFSET_ICS_VERSION (0x40)
#define CONFIG_REG_VIRT_ADDR_OFFSET_ICS_BASE_ADDR (0x28)
#define ICS_IRQ_OFFSET_ICS_IRQ_MASK_LPMCU_FINISH (0x20)
#define ICS_IRQ_OFFSET_ICS_IRQ_MASK_IOMCU_FINISH (0x30)
#define ICS_IRQ_OFFSET_ICS_IRQ_MASK_ISPCPU_FINISH (0x40)
#define ICS_IRQ_OFFSET_ICS_IRQ_MASK_IVP_FINISH (0x50)
#define ICS_IRQ_OFFSET_ICS_IRQ_MASK_HIFI_FINISH (0x60)
static struct class *ics_class;
struct cambricon_ipu_private *ics_adapter;
static uint32_t setclkrate = 0;
static uint32_t setprofile = 0;
static uint32_t ipuopen = 0;
static uint32_t ipurelease = 0;
static uint32_t ipuversion = 0;
static uint32_t resetproc = 0;
static uint32_t ipurstcrtenv = 0;
static uint32_t ipurstdstenv = 0;
static uint32_t pusetreg = 0;
static uint32_t pdsetreg = 0;
static uint32_t rdcorereg = 0;
static uint32_t wrcorereg = 0;
static uint32_t wrregvbusclk = 0;
static uint32_t wrregcnnclk = 0;
static uint32_t wrreglmt = 0;
struct ics_test_iomap_addr {
void __iomem *pmctrl_io_addr;
void __iomem *pctrl_io_addr;
void __iomem *sctrl_io_addr;
void __iomem *media_io_addr;
void __iomem *peri_io_addr;
};
struct ics_test_iomap_addr ics_test_iomap_addr;
unsigned long smmu_ttbr0_bk = 0;
static ssize_t setclkrate_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret = 0;
ret = snprintf(buf, PAGE_SIZE, "setclkrate:0x%x!\n", setclkrate);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo clockRate>setclkrate\n");
return ret;
}
static ssize_t setclkrate_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
int ret = 0;
if (sscanf(buf, "%d", &setclkrate) != 1)
return -EINVAL;
printk(KERN_DEBUG"[%s]: setclkrate_store begin\n", __FUNCTION__);
ics_adapter->clk.start_rate = setclkrate;
if (ret) {
printk(KERN_ERR"[%s]: call_ipu_clock_start failed\n", __FUNCTION__);
return -EINVAL;
}
printk(KERN_DEBUG"[%s]: setclkrate_store end\n", __FUNCTION__);
return (ssize_t)size;
}
static ssize_t setprofile_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret = 0;
ret = snprintf(buf, PAGE_SIZE, "setprofile:0x%x!\n", setprofile);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo profile>setprofile\n");
return ret;
}
static ssize_t setprofile_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
int ret = 0;
if (sscanf(buf, "%d", &setprofile) != 1)
return -EINVAL;
printk(KERN_DEBUG"[%s]: setclkrate_store begin\n", __FUNCTION__);
call_ipu_set_profile(setprofile);
if (ret) {
printk(KERN_ERR"[%s]: ipu_clock_set_profile failed\n", __FUNCTION__);
return -EINVAL;
}
printk(KERN_DEBUG"[%s]: setprofile_store end\n", __FUNCTION__);
return (ssize_t)size;
}
static ssize_t ipuopen_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret =0;
ret = snprintf(buf, PAGE_SIZE, "ipuopen:0x%x!\n", ipuopen);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>ipuopen\n");
return ret;
}
static ssize_t ipuopen_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
int ret = 0;
printk(KERN_DEBUG"[%s]: ipuopen_store begin\n", __FUNCTION__);
ret = call_regulator_ip_vipu_enable();
if (ret) {
printk(KERN_ERR"[%s]: call_regulator_ip_vipu_enable failed\n", __FUNCTION__);
return -EINVAL;
}
printk(KERN_DEBUG"[%s]: call_regulator_ip_vipu_enable ok\n", __FUNCTION__);
call_ipu_clock_start(&ics_adapter->clk);
if (ret) {
printk(KERN_ERR"[%s]: IPU clock start failed\n", __FUNCTION__);
return -EINVAL;
}
printk(KERN_DEBUG"[%s]: call_ipu_clock_start ok\n", __FUNCTION__);
call_ipu_smmu_init(ics_adapter->smmu_ttbr0,
(unsigned long)ics_adapter->smmu_rw_err_phy_addr, ics_adapter->feature_tree.smmu_port_select, ics_adapter->feature_tree.smmu_mstr_hardware_start);
printk(KERN_DEBUG"[%s]: call_ipu_smmu_init ok\n", __FUNCTION__);
call_ipu_interrupt_init();
printk(KERN_DEBUG"[%s]: call_ipu_interrupt_init ok\n", __FUNCTION__);
printk(KERN_DEBUG"[%s]: ipuopen_store end\n", __FUNCTION__);
return (ssize_t)size;
}
static ssize_t ipurelease_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret =0;
ret = snprintf(buf, PAGE_SIZE, "ipurelease:0x%x!\n", ipurelease);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>ipurelease\n");
return ret;
}
static ssize_t ipurelease_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
int ret = 0;
printk(KERN_DEBUG"[%s]: ipurelease_store begin\n", __FUNCTION__);
call_ipu_clock_set_rate(&ics_adapter->clk, ics_adapter->clk.stop_rate);
printk(KERN_DEBUG"[%s]: call_ipu_clock_set_rate ok\n", __FUNCTION__);
call_ipu_clock_stop(&ics_adapter->clk);
printk(KERN_DEBUG"[%s]: call_ipu_clock_stop ok\n", __FUNCTION__);
ret = call_regulator_ip_vipu_disable();
if (ret) {
printk(KERN_ERR"[%s]: No IPU device!\n", __FUNCTION__);
return -EBUSY;
}
printk(KERN_DEBUG"[%s]: call_regulator_ip_vipu_disable ok\n", __FUNCTION__);
ics_adapter->ipu_device_opened = 0;
printk(KERN_DEBUG"[%s]: ipurelease_store end\n", __FUNCTION__);
return (ssize_t)size;
}
static ssize_t ipuversion_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret =0;
unsigned int regval;
regval = ioread32((void *)((unsigned long)ics_adapter->config_reg_virt_addr + CONFIG_REG_VIRT_ADDR_OFFSET_ICS_VERSION));
ret = snprintf(buf, PAGE_SIZE, "ipuversion:0x%x, register value: 0x%x!\n", ipuversion, regval);
DEBUG("read version %x, cached %d", regval, ipuversion);
return ret;
}
static ssize_t ipuversion_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
int ret = 0, ver = 0;
if (sscanf(buf, "%x", &ver) != 1) {
printk(KERN_ERR "[%s]: version error, invalid number format!\n", __FUNCTION__);
return -EINVAL;
}
ipuversion = ver;
iowrite32(ver, (void *)((unsigned long)ics_adapter->config_reg_virt_addr + CONFIG_REG_VIRT_ADDR_OFFSET_ICS_VERSION));
DEBUG("write version %x", ver);
return (ssize_t)size;
}
static ssize_t resetproc_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret =0;
ret = snprintf(buf, PAGE_SIZE, "resetproc:0x%x!\n", resetproc);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>resetproc\n");
return ret;
}
static ssize_t resetproc_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
printk(KERN_DEBUG"[%s]: begin\n", __FUNCTION__);
call_ipu_reset_proc((unsigned int)ics_adapter->reset_va);
printk(KERN_DEBUG"[%s]: end\n", __FUNCTION__);
return (ssize_t)size;
}
static ssize_t ipurstcrtenv_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret =0;
ret = snprintf(buf, PAGE_SIZE, "ipu reset create environment:0x%x!\n", ipurstcrtenv);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>ipurstcrtenv (no need to pu ipu)\n");
return ret;
}
static ssize_t ipurstcrtenv_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
printk(KERN_DEBUG"[%s]: begin\n", __FUNCTION__);
smmu_ttbr0_bk = ics_adapter->smmu_ttbr0;
ics_adapter->smmu_ttbr0 = smmu_ttbr0_bk & 0xffffffff;
printk(KERN_DEBUG"[%s]: end\n", __FUNCTION__);
return (ssize_t)size;
}
static ssize_t ipurstdstenv_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret =0;
ret = snprintf(buf, PAGE_SIZE, "ipu reset destroy environment:0x%x!\n", ipurstdstenv);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>ipurstcrtenv (no need to pu ipu)\n");
return ret;
}
static ssize_t ipurstdstenv_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
printk(KERN_DEBUG"[%s]: begin\n", __FUNCTION__);
ics_adapter->smmu_ttbr0 = smmu_ttbr0_bk;
printk(KERN_DEBUG"[%s]: end\n", __FUNCTION__);
return (ssize_t)size;
}
static ssize_t pusetreg_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret = 0;
ret = snprintf(buf, PAGE_SIZE, "pusetreg:0x%x!\n", pusetreg);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>pusetreg\n");
return ret;
}
static ssize_t pusetreg_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
unsigned int read_value;
printk(KERN_DEBUG"[%s]: peri_io_addr:%p, media2_io_addr:%p, pmctrl_io_addr=%p\n", __FUNCTION__,
ics_adapter->peri_io_addr, ics_adapter->media2_io_addr, ics_adapter->pmctrl_io_addr);
//set_pu_media2_subsys
printk(KERN_DEBUG"[%s]:meidia module unrst\n",__FUNCTION__);
iowrite32(PERI_PERRSTDIS4_IP_RST_MEDIA2_CRG_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PERRSTDIS4));
printk(KERN_DEBUG"[%s]:meidia module clk enable\n",__FUNCTION__);
iowrite32(PERI_PEREN6_GT_CLK_CFGBUS_MEDIA_AND_MEDIA2_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PEREN6));
udelay(1);
printk(KERN_DEBUG"[%s]:meidia module clk disable\n",__FUNCTION__);
iowrite32(PERI_PERDIS6_GT_CLK_CFGBUS_MEDIA_AND_MEDIA2_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PERDIS6));
udelay(1);
printk(KERN_DEBUG"[%s]:meidia module unrst\n",__FUNCTION__);
iowrite32(PERI_PERRSTDIS4_IP_RST_MEDIA2, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PERRSTDIS4));
printk(KERN_DEBUG"[%s]:meidia module clk enable\n",__FUNCTION__);
iowrite32(PERI_PEREN6_GT_CLK_CFGBUS_MEDIA_AND_MEDIA2_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PEREN6));
//set_pu_vcodec
printk(KERN_DEBUG"[%s]:vcodec module clk enable\n",__FUNCTION__);
iowrite32(PERI_CLKDIV18_SC_GT_CLK_VCODEBUS_OPEN_AND_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV18));
iowrite32(MEDIA2_PEREN0_GT_CLK_VCODEBUS_EN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PEREN0));
iowrite32(PERI_PEREN0_GT_CLK_VCODECBUS2DDRC_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PEREN0));
udelay(1);
printk(KERN_DEBUG"[%s]:vcodec module clk disable\n",__FUNCTION__);
iowrite32(MEDIA2_PERDIS0_GT_CLK_VCODEBUS_UN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PERDIS0));
iowrite32(PERI_PERDIS0_GT_CLK_VCODECBUS2DDRC_UN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PERDIS0));
udelay(1);
printk(KERN_DEBUG"[%s]:vcodec module clk enable\n",__FUNCTION__);
iowrite32(MEDIA2_PEREN0_GT_CLK_VCODEBUS_EN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PEREN0));
iowrite32(PERI_PEREN0_GT_CLK_VCODECBUS2DDRC_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PEREN0));
printk(KERN_DEBUG"[%s]:vcodec bus idle clear\n",__FUNCTION__);
iowrite32(PMCTRL_NOC_NOC_POWER_IDLEREQ_0_NOC_VCODEC_BUS_POWER_IDLEREQ_EN, (void *)((unsigned long)ics_adapter->pmctrl_io_addr+ PMCTRL_OFFSET_NOC_POWER_IDLEREQ_0));
udelay(1);
read_value = ioread32((void *)((unsigned long)ics_adapter->pmctrl_io_addr+ PMCTRL_OFFSET_NOC_POWER_IDLEACK_0));
if ((PMCTRL_NOC_POWER_IDLEACK_0_NOC_VCODEC_BUS_POWER_IDLEACK & PMCTRL_NOC_POWER_IDLEACK_0_NOC_VCODEC_BUS_POWER_IDLEACK_UN) != 0x0) {
printk(KERN_ERR"[%s]: pu_codec:no expect power idleack value:%d!\n",
__FUNCTION__ , read_value);
return -EINVAL;
}
udelay(1);
read_value = ioread32((void *)((unsigned long)ics_adapter->pmctrl_io_addr + PMCTRL_OFFSET_NOC_POWER_IDLE_0));
if ((read_value & PMCTRL_NOC_POWER_IDLE_0_NOC_VCODEC_BUS_POWER_IDLE_STATUS) != PMCTRL_NOC_POWER_IDLE_0_NOC_VCODEC_BUS_POWER_IDLE_STATUS_UN) {
printk(KERN_ERR"[%s]: pu_codec:no expect power idle value:%d!\n",
__FUNCTION__ , read_value);
return -EINVAL;
}
//set_pu_ics
printk(KERN_DEBUG"[%s]:ipu module mtcmos on\n",__FUNCTION__);
iowrite32(PERI_PERPWREN_ICSPWREN_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PERPWREN));
udelay(100);
printk(KERN_DEBUG"[%s]:ipu module clk enable\n",__FUNCTION__);
iowrite32(PERI_CLKDIV18_SC_GT_CLK_ICS_OPEN_AND_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV18));
iowrite32(MEDIA2_PEREN0_GT_CLK_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_EN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PEREN0));
udelay(1);
printk(KERN_DEBUG"[%s]:ipu module clk disable\n",__FUNCTION__);
iowrite32(MEDIA2_PERDIS0_GT_CLK_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_UN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PERDIS0));
udelay(1);
printk(KERN_DEBUG"[%s]:ipu module iso disable\n",__FUNCTION__);
iowrite32(PERI_ISODIS_ICS_ISO_UN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_ISODIS));
printk(KERN_DEBUG"[%s]:ipu module unrst\n",__FUNCTION__);
iowrite32(MEDIA2_PERRSTDIS0_IP_RST_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_UN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PERRSTDIS0));
udelay(1);
printk(KERN_DEBUG"[%s]:ipu module clk enable\n",__FUNCTION__);
iowrite32(MEDIA2_PEREN0_GT_CLK_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_EN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PEREN0));
printk(KERN_DEBUG"[%s]:ipu bus idle clear\n",__FUNCTION__);
iowrite32(PMCTRL_NOC_POWER_IDLEREQ_0_NOC_ICS_POWER_IDLEREQ_EN, (void *)((unsigned long)ics_adapter->pmctrl_io_addr+ PMCTRL_OFFSET_NOC_POWER_IDLEREQ_0));
udelay(1);
read_value = ioread32((void *)((unsigned long)ics_adapter->pmctrl_io_addr+ PMCTRL_OFFSET_NOC_POWER_IDLEACK_0));
if ((read_value & PMCTRL_NOC_POWER_IDLEACK_0_NOC_ICS_POWER_IDLEACK) != PMCTRL_NOC_POWER_IDLEACK_0_NOC_ICS_POWER_IDLEACK_UN) {
printk(KERN_ERR"[%s]: pu_ics:no expect power idleack value:%d!\n",
__FUNCTION__ , read_value);
return -EINVAL;
}
udelay(1);
read_value = ioread32((void *)((unsigned long)ics_adapter->pmctrl_io_addr+ PMCTRL_OFFSET_NOC_POWER_IDLE_0));
if ((read_value & PMCTRL_NOC_POWER_IDLE_0_NOC_ICS_POWER_IDLE) != PMCTRL_NOC_POWER_IDLE_0_NOC_ICS_POWER_IDLE_UN) {
printk(KERN_ERR"[%s]: pu_ics:no expect power idle value:%d!\n",
__FUNCTION__ , read_value);
return -EINVAL;
}
return (ssize_t)size;
}
static ssize_t pdsetreg_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret = 0;
ret = snprintf(buf, PAGE_SIZE, "pdsetreg:0x%x!\n", pdsetreg);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>pdsetreg\n");
return ret;
}
static ssize_t pdsetreg_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
unsigned int read_value;
//set_pd_ics
printk(KERN_DEBUG"[%s]:ipu bus idle set\n",__FUNCTION__);
iowrite32(PMCTRL_NOC_POWER_IDLEREQ_0_NOC_ICS_POWER_IDLEREQ_REQ_AND_EN, (void *)((unsigned long)ics_adapter->pmctrl_io_addr+ PMCTRL_OFFSET_NOC_POWER_IDLEREQ_0));
udelay(1);
read_value = ioread32((void *)((unsigned long)ics_adapter->pmctrl_io_addr+ PMCTRL_OFFSET_NOC_POWER_IDLEACK_0));
if((read_value & PMCTRL_NOC_POWER_IDLEACK_0_NOC_ICS_POWER_IDLEACK) != PMCTRL_NOC_POWER_IDLEACK_0_NOC_ICS_POWER_IDLEACK_EN) {
printk(KERN_ERR"[%s]: pd_ics:no expect power idleack value:%d!\n",
__FUNCTION__ , read_value);
return -EINVAL;
}
udelay(1);
read_value = ioread32((void *)((unsigned long)ics_adapter->pmctrl_io_addr+ PMCTRL_OFFSET_NOC_POWER_IDLE_0));
if((read_value & PMCTRL_NOC_POWER_IDLE_0_NOC_ICS_POWER_IDLE) != PMCTRL_NOC_POWER_IDLE_0_NOC_ICS_POWER_IDLE_EN) {
printk(KERN_ERR"[%s]: pd_ics:no expect power idle value:%d!\n",
__FUNCTION__ , read_value);
return -EINVAL;
}
printk(KERN_DEBUG"[%s]:ipu module clk disable\n",__FUNCTION__);
iowrite32(MEDIA2_PERDIS0_GT_CLK_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_UN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PERDIS0));
udelay(1);
printk(KERN_DEBUG"[%s]:ipu module rst\n",__FUNCTION__);
iowrite32(MEDIA2_PERRSTEN0_IP_RST_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_EN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PERRSTEN0));
udelay(1);
printk(KERN_DEBUG"[%s]:ipu module clk disable\n",__FUNCTION__);
iowrite32(MEDIA2_PEREN0_GT_CLK_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_EN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PEREN0));
udelay(1);
printk(KERN_DEBUG"[%s]:ipu module clk disable\n",__FUNCTION__);
iowrite32(MEDIA2_PERDIS0_GT_CLK_ICS_AND_NOC_ICS_AND_NOC_ICS_CFG_UN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PERDIS0));
iowrite32(PERI_CLKDIV18_SC_GT_CLK_ICS__EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV18));
printk(KERN_DEBUG"[%s]:ipu module iso\n",__FUNCTION__);
iowrite32(PERI_ISOEN_ICS_ISO_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_ISOEN));
printk(KERN_DEBUG"[%s]:ipu module mtcmos off\n",__FUNCTION__);
iowrite32(PERI_PERPWRDIS_ICS_PWR_DIS, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PERPWRDIS));
//set_pd_vcodec
printk(KERN_DEBUG"[%s]:vcodec bus idle set\n",__FUNCTION__);
iowrite32(PMCTRL_NOC_NOC_POWER_IDLEREQ_0_NOC_VCODEC_BUS_POWER_IDLEREQ_REQ_AND_EN, (void *)((unsigned long)ics_adapter->pmctrl_io_addr+ PMCTRL_OFFSET_NOC_POWER_IDLEREQ_0));
udelay(1);
read_value = ioread32((void *)((unsigned long)ics_adapter->pmctrl_io_addr+ PMCTRL_OFFSET_NOC_POWER_IDLEACK_0));
if((read_value & PMCTRL_NOC_POWER_IDLEACK_0_NOC_VCODEC_BUS_POWER_IDLEACK) != PMCTRL_NOC_POWER_IDLEACK_0_NOC_VCODEC_BUS_POWER_IDLEACK_EN) {
printk(KERN_ERR"[%s]: pd_codec:no expect power idleack value:%d!\n",
__FUNCTION__ , read_value);
return -EINVAL;
}
udelay(1);
read_value = ioread32((void *)((unsigned long)ics_adapter->pmctrl_io_addr+ PMCTRL_OFFSET_NOC_POWER_IDLE_0));
if((read_value & PMCTRL_NOC_POWER_IDLE_0_NOC_VCODEC_BUS_POWER_IDLE_STATUS) != PMCTRL_NOC_POWER_IDLE_0_NOC_VCODEC_BUS_POWER_IDLE_STATUS_EN) {
printk(KERN_ERR"[%s]: pd_codec:no expect power idle value:%d!\n",
__FUNCTION__ , read_value);
return -EINVAL;
}
printk(KERN_DEBUG"[%s]:vcodec module clk disable\n",__FUNCTION__);
iowrite32(MEDIA2_PERDIS0_GT_CLK_VCODEBUS_UN, (void *)((unsigned long)ics_adapter->media2_io_addr + MEDIA2_OFFSET_PERDIS0));
iowrite32(PERI_PERDIS0_GT_CLK_VCODECBUS2DDRC_UN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PERDIS0));
iowrite32(PERI_CLKDIV18_SC_GT_CLK_VCODEBUS_EN, (void *)((unsigned long)ics_adapter->peri_io_addr+ PERI_OFFSET_CLKDIV18));
//set_pu_media2_subsys
printk(KERN_DEBUG"[%s]:media module rst\n",__FUNCTION__);
iowrite32(PERI_PERRSTEN4_IP_RST_MEDIA2_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PERRSTEN4));
printk(KERN_DEBUG"[%s]:media module clk disable\n",__FUNCTION__);
iowrite32(PERI_PERDIS6_GT_CLK_CFGBUS_MEDIA_AND_MEDIA2_EN, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PERDIS6));
printk(KERN_DEBUG"[%s]:media module unrst\n",__FUNCTION__);
iowrite32(PERI_PERRSTEN4_IP_RST_MEDIA_CRG, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_PERRSTEN4));
return (ssize_t)size;
}
static ssize_t rdcorereg_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret = 0;
ret = snprintf(buf, PAGE_SIZE, "rdcorereg:0x%x!\n", rdcorereg);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>rdcorereg\n");
return ret;
}
static ssize_t rdcorereg_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
unsigned int read_value;
read_value = ioread32((void *)((unsigned long)ics_adapter->config_reg_virt_addr + CONFIG_REG_VIRT_ADDR_OFFSET_ICS_VERSION));
if (read_value != 0x44400a7c && read_value != 0x4440031b) {
printk(KERN_ERR"[%s]: read_value error : 0x%x!\n", __FUNCTION__ , read_value);
return -EINVAL;
}
return (ssize_t)size;
}
static ssize_t wrcorereg_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret =0;
u32 value = 0;
ret = snprintf(buf, PAGE_SIZE, "wrcorereg:0x%x!\n", wrcorereg);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>wrcorereg\n");
value = ioread32((void *)((unsigned long)ics_adapter->config_reg_virt_addr + CONFIG_REG_VIRT_ADDR_OFFSET_ICS_BASE_ADDR));
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "register value: %u\n", value);
return ret;
}
static ssize_t wrcorereg_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
unsigned int read_value;
if (sscanf(buf, "0x%x", &wrcorereg) != 1)
return -EINVAL;
iowrite32(wrcorereg, (void *)((unsigned long)ics_adapter->config_reg_virt_addr + CONFIG_REG_VIRT_ADDR_OFFSET_ICS_BASE_ADDR));
udelay(1);
read_value = ioread32((void *)((unsigned long)ics_adapter->config_reg_virt_addr + CONFIG_REG_VIRT_ADDR_OFFSET_ICS_BASE_ADDR));
if (read_value != wrcorereg) {
printk(KERN_ERR"[%s]: read_value error : 0x%x!\n", __FUNCTION__ , read_value);
return -EINVAL;
} else {
printk(KERN_DEBUG "[%s]: write %lx success!\n", __FUNCTION__, (unsigned long)ics_adapter->config_reg_virt_addr + CONFIG_REG_VIRT_ADDR_OFFSET_ICS_BASE_ADDR);
}
return (ssize_t)size;
}
static ssize_t wrregvbusclk_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret = 0;
ret = snprintf(buf, PAGE_SIZE, "wrregvbusclk:0x%x!\n", wrregvbusclk);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>wrregvbusclk\n");
return ret;
}
static ssize_t wrregvbusclk_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
if (sscanf(buf, "%d", &wrregvbusclk) != 1)
return -EINVAL;
if (wrregvbusclk != 480000000 && wrregvbusclk != 322000000 && wrregvbusclk != 207500000) {
return -EINVAL;
}
if (wrregvbusclk == 480000000) {
iowrite32(PERI_CLKDIV8_SEL_VCODECBUS_PLL2, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV8));
iowrite32(PERI_CLKDIV5_SET_FREQ_DIV4_VCODECBUS, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV5));
} else if(wrregvbusclk == 322000000){
iowrite32(PERI_CLKDIV8_SEL_VCODECBUS_PLL0, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV8));
iowrite32(PERI_CLKDIV5_SET_FREQ_DIV5_VCODECBUS, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV5));
} else if(wrregvbusclk == 207500000){
iowrite32(PERI_CLKDIV8_SEL_VCODECBUS_PLL0, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV8));
iowrite32(PERI_CLKDIV5_SET_FREQ_DIV8_VCODECBUS, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV5));
}
return (ssize_t)size;
}
static ssize_t wrregcnnclk_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret = 0;
ret = snprintf(buf, PAGE_SIZE, "wrregcnnclk:0x%x!\n", wrregcnnclk);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>wrregcnnclk\n");
return ret;
}
static ssize_t wrregcnnclk_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
if (sscanf(buf, "%d", &wrregcnnclk) != 1)
return -EINVAL;
if (wrregcnnclk != 960000000 && wrregvbusclk != 640000000 && wrregvbusclk != 415000000) {
return -EINVAL;
}
if (wrregcnnclk == 960000000) {
iowrite32(PERI_CLKDIV8_SEL_ICS_PLL2, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV8));
iowrite32(PERI_CLKDIV15_SEL_FREQ_DIV2_ICS, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV15));
} else if (wrregcnnclk == 640000000) {
iowrite32(PERI_CLKDIV8_SEL_ICS_PLL2, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV8));
iowrite32(PERI_CLKDIV15_SEL_FREQ_DIV3_ICS, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV15));
} else if (wrregcnnclk == 415000000) {
iowrite32(PERI_CLKDIV8_SEL_ICS_PLL0, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV8));
iowrite32(PERI_CLKDIV15_SEL_FREQ_DIV4_ICS, (void *)((unsigned long)ics_adapter->peri_io_addr + PERI_OFFSET_CLKDIV15));
}
return (ssize_t)size;
}
static ssize_t wrreglmt_show(struct class *class, struct class_attribute *attr,
char *buf)
{
int ret = 0;
ret = snprintf(buf, PAGE_SIZE, "wrreglmt:0x%x!\n", wrreglmt);
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "usage: echo param>wrreglmt_es\n");
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "wrreglmt = 0xf6b ,ics core:400M,vcodec bus:207.5M\n");
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "wrreglmt = 0xaaa,ics core:640M,vcodec bus:480M\n");
ret += snprintf(buf+ret, (PAGE_SIZE-ret), "wrreglmt = 0xdd5 ,ics core:830M,vcodec bus:480M\n");
return ret;
}
static ssize_t wrreglmt_store(struct class *class, struct class_attribute *attr,
const char *buf, size_t size)
{
void __iomem *axi;
unsigned int read_value = 0;
if (sscanf(buf, "0x%x", &wrreglmt) != 1)
return -EINVAL;
if (wrreglmt != 0xf6b &&
wrreglmt != 0xaaa &&
wrreglmt != 0xdd5 ) {
printk(KERN_ERR"[%s]: limiter:input error value:%d!\n",
__FUNCTION__ , wrreglmt);
return -EINVAL;
}
axi = ioremap((unsigned long)0xe8950000,(unsigned long)0xfff);
iowrite32(0x1,(void *)((unsigned long)axi+0x0c));
udelay(10);
iowrite32(wrreglmt,(void *)((unsigned long)axi+0x10));
udelay(10);
iowrite32(0x40, (void *)((unsigned long)axi+0x14));
read_value = ioread32((void *)((unsigned long)axi+ 0x10));
printk(KERN_DEBUG"[%s]:limit value = 0x%x",__FUNCTION__, read_value);
iounmap(axi);
return (ssize_t)size;
}
static const struct class_attribute ics_attrs[] = {
__ATTR(setclkrate, 0644, setclkrate_show, setclkrate_store),
__ATTR(setprofile, 0644, setprofile_show, setprofile_store),
__ATTR(ipuopen, 0644, ipuopen_show, ipuopen_store),
__ATTR(ipurelease, 0644, ipurelease_show, ipurelease_store),
__ATTR(ipuversion, 0644, ipuversion_show, ipuversion_store),
__ATTR(resetproc, 0644, resetproc_show, resetproc_store),
__ATTR(ipurstcrtenv, 0644, ipurstcrtenv_show, ipurstcrtenv_store),
__ATTR(ipurstdstenv, 0644, ipurstdstenv_show, ipurstdstenv_store),
__ATTR(pusetreg, 0644, pusetreg_show, pusetreg_store),
__ATTR(pdsetreg, 0644, pdsetreg_show, pdsetreg_store),
__ATTR(rdcorereg, 0644, rdcorereg_show, rdcorereg_store),
__ATTR(wrcorereg, 0644, wrcorereg_show, wrcorereg_store),
__ATTR(wrregvbusclk, 0644, wrregvbusclk_show, wrregvbusclk_store),
__ATTR(wrregcnnclk, 0644, wrregcnnclk_show, wrregcnnclk_store),
__ATTR(wrreglmt, 0644, wrreglmt_show, wrreglmt_store),
};
static int create_ics_attrs(struct class *class)
{
unsigned int i = 0;
int ret = 0;
for (i = 0; i < (sizeof(ics_attrs)/sizeof(struct class_attribute)); i++) {
ret = class_create_file(class, &ics_attrs[i]);
if (ret < 0) {
break;
}
}
return ret;
}
static void remove_ics_attrs(struct class *class)
{
unsigned int i = 0;
for (i = 0; i < (sizeof(ics_attrs)/sizeof(struct class_attribute)); i++) {
class_remove_file(class, &ics_attrs[i]);
}
}
static int __init ics_debug_init(void) {
int ret = 0;
printk(KERN_ERR"[%s:%d], test begin\n", __FUNCTION__, __LINE__);
ics_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(ics_class)) {
printk(KERN_ERR"[%s:%d], class create error!\n", __FUNCTION__, __LINE__);
return -EFAULT;
}
ret = create_ics_attrs(ics_class);
if(ret < 0) {
class_destroy(ics_class);
printk(KERN_ERR"[%s:%d], create_ics_attrs error!\n", __FUNCTION__, __LINE__);
return -EFAULT;
}
ics_adapter = get_ipu_adapter();
return 0;
}
static void __exit ics_debug_exit(void) {
printk(KERN_ERR"[%s:%d], test end\n", __FUNCTION__, __LINE__);
remove_ics_attrs(ics_class);
class_destroy(ics_class);
return;
}
module_init(ics_debug_init);
module_exit(ics_debug_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Hisilicon");
+6
View File
@@ -0,0 +1,6 @@
#ifndef __ICS_DEBUG_H__
#define __ICS_DEBUG_H__
#include "ics_debug_proxy.h"
#endif
+77
View File
@@ -0,0 +1,77 @@
#include "ipu_clock.h"
#include "ipu_smmu_drv.h"
#include "ics_debug_proxy.h"
struct ioctl_out_params {
bool ret_directly;
void *memory_node;
//TODO: add more out params here
};
extern struct cambricon_ipu_private *adapter;
extern int regulator_ip_vipu_enable(void);
extern int regulator_ip_vipu_disable(void);
extern void ipu_reset_proc(unsigned int addr);
extern void ipu_interrupt_init(void);
extern long ipu_set_profile(struct cambricon_ipu_private *, unsigned long, struct ioctl_out_params *);
int call_regulator_ip_vipu_enable(void)
{
return regulator_ip_vipu_enable();
}
EXPORT_SYMBOL(call_regulator_ip_vipu_enable);
int call_regulator_ip_vipu_disable(void)
{
return regulator_ip_vipu_disable();
}
EXPORT_SYMBOL(call_regulator_ip_vipu_disable);
void call_ipu_reset_proc(unsigned int addr)
{
ipu_reset_proc(addr);
}
EXPORT_SYMBOL(call_ipu_reset_proc);
void call_ipu_interrupt_init(void)
{
ipu_interrupt_init();
}
EXPORT_SYMBOL(call_ipu_interrupt_init);
void * get_ipu_adapter(void)
{
return adapter;
}
EXPORT_SYMBOL(get_ipu_adapter);
int call_ipu_clock_start(void *clock)
{
return ipu_clock_start(clock);
}
EXPORT_SYMBOL(call_ipu_clock_start);
int call_ipu_clock_set_rate(void *clock, unsigned int clock_rate)
{
return ipu_clock_set_rate(clock, clock_rate);
}
EXPORT_SYMBOL(call_ipu_clock_set_rate);
void call_ipu_clock_stop(void *clock)
{
ipu_clock_stop(clock);
}
EXPORT_SYMBOL(call_ipu_clock_stop);
void call_ipu_smmu_init(unsigned long ttbr0, unsigned long smmu_rw_err_phy_addr, bool port_sel, bool hardware_start)
{
ipu_smmu_init(ttbr0, smmu_rw_err_phy_addr, port_sel, hardware_start);
}
EXPORT_SYMBOL(call_ipu_smmu_init);
void call_ipu_set_profile(unsigned long profile)
{
ipu_set_profile(0, profile, 0);
}
EXPORT_SYMBOL(call_ipu_set_profile);
+17
View File
@@ -0,0 +1,17 @@
#ifndef __ICS_DEBUG_PROXY_H__
#define __ICS_DEBUG_PROXY_H__
#include "cambricon_ipu.h"
int call_regulator_ip_vipu_enable(void);
int call_regulator_ip_vipu_disable(void);
void call_ipu_reset_proc(unsigned int addr);
void call_ipu_interrupt_init(void);
void * get_ipu_adapter(void);
int call_ipu_clock_start(void *clk);
int call_ipu_clock_set_rate(void *clock, unsigned int clock_rate);
void call_ipu_clock_stop(void *clock);
void call_ipu_smmu_init(unsigned long ttbr0, unsigned long smmu_rw_err_phy_addr, bool port_sel, bool hardware_start);
void call_ipu_set_profile(unsigned long profile);
#endif
+233
View File
@@ -0,0 +1,233 @@
#include <linux/errno.h>
#include <linux/clk-provider.h>
#include "ipu_clock.h"
// #include "ipu_mntn.h"
#include "cambricon_ipu.h"
// #define CONFIG_IPU_CLOCK_CONTROL
extern struct cambricon_ipu_private *adapter;
/* this func use mutex, for interface only, and SHOULD NOT be called by other ipu_clock functions */
int ipu_clock_init(struct device *dev, struct ics_clock *clk, bool lpm3_set_vcodecbus)
{
int property_rd;
struct device_node *node;
mutex_lock(&clk->clk_mutex);
clk->lpm3_set_vcodecbus = lpm3_set_vcodecbus;
/* get clock of "clk-ics" from CLK API */
clk->ipu_clk_ptr = devm_clk_get(dev, "clk-ics");
if (IS_ERR_OR_NULL(clk->ipu_clk_ptr)) {
printk(KERN_ERR"[%s]: IPU_ERROR:get clock failed, ipu_clk_ptr is %pK\n", __func__, clk->ipu_clk_ptr);
mutex_unlock(&clk->clk_mutex);
return -ENODEV;
}
clk->vcodecbus_clk_ptr = devm_clk_get(dev, "clk_vcodecbus");
printk(KERN_DEBUG "[%s]: IPU_DEBUG vcodecbus_clk_ptr is %pK\n", __func__, clk->vcodecbus_clk_ptr);
#ifdef CONFIG_HISI_IPU_SET_VCODECBUS
if (IS_ERR_OR_NULL(clk->vcodecbus_clk_ptr)) {
printk(KERN_ERR"[%s]: IPU_ERROR:get clock failed, vcodecbus_clk_ptr is %pK\n", __func__, clk->vcodecbus_clk_ptr);
mutex_unlock(&clk->clk_mutex);
return -ENODEV;
}
#endif
node = of_find_node_by_name(dev->of_node, "ipu-and-vcodecbus-clock-rate");
if(!node) {
printk(KERN_ERR"[%s]: IPU_ERROR:find clock node error\n", __func__);
mutex_unlock(&clk->clk_mutex);
return -ENODEV;
}
property_rd = of_property_read_u32(node, "start-rate", &clk->start_rate);
property_rd |= of_property_read_u32(node, "stop-rate", &clk->stop_rate);
property_rd |= of_property_read_u32(node, "ipu-low", &clk->ipu_low);
property_rd |= of_property_read_u32(node, "ipu-middle", &clk->ipu_middle);
property_rd |= of_property_read_u32(node, "ipu-high", &clk->ipu_high);
property_rd |= of_property_read_u32(node, "ipu-low-temperature", &clk->ipu_low_temperature);
property_rd |= of_property_read_u32(node, "vcodecbus-low", &clk->vcodecbus_low);
property_rd |= of_property_read_u32(node, "vcodecbus-middle", &clk->vcodecbus_middle);
property_rd |= of_property_read_u32(node, "vcodecbus-high", &clk->vcodecbus_high);
property_rd |= of_property_read_u32(node, "vcodecbus-default", &clk->vcodecbus_default);
property_rd |= of_property_read_u32(node, "vcodecbus-high2default", &clk->vcodecbus_high2default);
if (property_rd) {
printk(KERN_ERR"[%s]: IPU_ERROR:read property of clock error\n", __func__);
mutex_unlock(&clk->clk_mutex);
return -ENODEV;
}
#ifdef CONFIG_ES_VDEC_LOW_FREQ
clk->vcodecbus_high = clk->vcodecbus_middle;
clk->ipu_high = clk->ipu_middle;
clk->start_rate = clk->ipu_middle;
#endif
printk(KERN_DEBUG"[%s]: get clk rate done, start clk rate:%u, stop clk rate:%u\n",
__func__, clk->start_rate, clk->stop_rate);
clk->curr_rate = IPU_CLOCK_UNSET;
mutex_unlock(&clk->clk_mutex);
return 0;
}
static int ipu_clock_set(struct ics_clock *clk, unsigned int new_rate)
{
int ret;
unsigned int target_rate = new_rate;
if (new_rate == clk->curr_rate) {
printk(KERN_ERR"[%s]: IPU_WARN:set some IPU clock rate %d, ignored\n", __func__, target_rate);
return 0;
}
#ifdef CONFIG_IPU_CLOCK_CONTROL
if (clk->ipu_high == target_rate) {
/* for HIGH, set IPU clock to HIGH */
ret = clk_set_rate(clk->ipu_clk_ptr, (unsigned long)target_rate);
if (ret) {
/* in low temperature, clk set rate to HIGH will fail, in this case try to set rate to another rate */
printk(KERN_ERR"[%s]: IPU_ERROR:set ipu rate %d fail (possible in low temperature), ret:%d, try to set %d\n",
__func__, target_rate, ret, clk->ipu_low_temperature);
target_rate = clk->ipu_low_temperature;
ret = clk_set_rate(clk->ipu_clk_ptr, (unsigned long)target_rate);
if (ret) {
printk(KERN_ERR"[%s]: IPU_ERROR:set ipu rate %d fail, ret:%d\n", __func__, target_rate, ret);
rdr_system_error((unsigned int)MODID_NPU_EXC_SET_BACK_CLOCK_FAIL, 0, 0);
return ret;
}
} else {
#ifdef CONFIG_HISI_IPU_SET_VCODECBUS
if (!clk->lpm3_set_vcodecbus) {
/* for HIGH set IPU rate ok, set VCODECBUS to HIGH */
ret = clk_set_rate(clk->vcodecbus_clk_ptr, clk->vcodecbus_high);
if (ret) {
printk(KERN_ERR"[%s]: IPU_ERROR:set vcodec rate %d fail, ret:%d, ignore\n", __func__, clk->vcodecbus_high, ret);
}
}
#endif
}
} else {
#ifdef CONFIG_HISI_IPU_SET_VCODECBUS
/* for MIDDLE or LOW, set VCODECBUS to default if necessary (when alter from HIGH) */
if (!clk->lpm3_set_vcodecbus && clk->ipu_high == clk->curr_rate) {
/* set vcodec bus to "VCODECBUS_CLOCK_DEFAULT", which is used as the default rate for VENC/VDEC */
ret = clk_set_rate(clk->vcodecbus_clk_ptr, clk->vcodecbus_high2default);
if (ret) {
printk(KERN_ERR"[%s]: IPU_ERROR:set vcodec rate %d fail, ret:%d, ignore\n", __func__, clk->vcodecbus_high2default, ret);
}
ret = clk_set_rate(clk->vcodecbus_clk_ptr, clk->vcodecbus_default);
if (ret) {
printk(KERN_ERR"[%s]: IPU_ERROR:set vcodec rate %d fail, ret:%d, ignore\n", __func__, clk->vcodecbus_default, ret);
}
}
#endif
ret = clk_set_rate(clk->ipu_clk_ptr, (unsigned long)target_rate);
if (ret) {
/* in low temperature, clk set rate to HIGH will fail, in this case try to set rate to MIDDLE */
printk(KERN_ERR"[%s]: IPU_ERROR:set ipu rate %d fail, ret:%d\n", __func__, target_rate, ret);
rdr_system_error((unsigned int)MODID_NPU_EXC_SET_CLOCK_FAIL, 0, 0);
return ret;
}
}
#ifdef CONFIG_HISI_IPU_SET_VCODECBUS
printk(KERN_ERR"[%s]: IPU_NOTE: set clock done, ipu clock(try/actually/clk_get)=%d/%d/%ld, vcodecbus clock=%ld\n",
__func__, new_rate, target_rate, clk_get_rate(clk->ipu_clk_ptr), clk_get_rate(clk->vcodecbus_clk_ptr));
#else
printk(KERN_ERR"[%s]: IPU_NOTE: set clock done, ipu clock(try/actually/clk_get)=%d/%d/%ld\n",
__func__, new_rate, target_rate, clk_get_rate(clk->ipu_clk_ptr));
#endif
#endif // CONFIG_IPU_CLOCK_CONTROL
clk->curr_rate = target_rate;
return 0;
}
/* this func use mutex, for interface only, and SHOULD NOT be called by other ipu_clock functions */
int ipu_clock_start(struct ics_clock *clk)
{
int ret = 0;
mutex_lock(&clk->clk_mutex);
#ifdef CONFIG_IPU_CLOCK_CONTROL
/* WARNING: clk_prepare_enable should NOT be called in interrupt because it contains mutex.
If needed in furture, use API: clk_prepare and clk_enable instead of clk_prepare_enable
in interrupt functions. */
ret = clk_prepare_enable(clk->ipu_clk_ptr);
#endif
if (ret) {
printk(KERN_ERR"[%s]: IPU_ERROR:clk prepare enable failed,ret=%d\n", __func__, ret);
mutex_unlock(&clk->clk_mutex);
return ret;
}
/* NOTE: here need not call "clk_prepare_enable(clk->vcodecbus_clk_ptr)" because because it is used by both IPU and VCODEC
process can guarentee it!! */
clk->curr_rate = IPU_CLOCK_UNSET;
ret = ipu_clock_set(clk, clk->start_rate);
if (ret) {
printk(KERN_ERR"[%s]: IPU_ERROR:ipu_clock_set_rate failed,ret=%d\n", __func__, ret);
mutex_unlock(&clk->clk_mutex);
return ret;
}
mutex_unlock(&clk->clk_mutex);
return 0;
}
/* this func use mutex, for interface only, and SHOULD NOT be called by other ipu_clock functions */
int ipu_clock_set_start_rate(struct ics_clock *clk, unsigned int new_rate)
{
mutex_lock(&clk->clk_mutex);
if (clk->ipu_high == new_rate ||
clk->ipu_middle == new_rate ||
clk->ipu_low == new_rate) {
/* vote voltage hold lock if neccessary */
clk->start_rate = new_rate;
mutex_unlock(&clk->clk_mutex);
return 0;
} else {
printk(KERN_ERR"[%s]: IPU_ERROR:invalid start rate=%u\n", __func__, new_rate);
mutex_unlock(&clk->clk_mutex);
return -EINVAL;
}
}
/* this func use mutex, for interface only, and SHOULD NOT be called by other ipu_clock functions */
int ipu_clock_set_rate(struct ics_clock *clk, unsigned int new_rate)
{
int ret;
mutex_lock(&clk->clk_mutex);
ret = ipu_clock_set(clk, new_rate);
mutex_unlock(&clk->clk_mutex);
return ret;
}
/* this func use mutex, for interface only, and SHOULD NOT be called by other ipu_clock functions */
void ipu_clock_stop(struct ics_clock *clk)
{
mutex_lock(&clk->clk_mutex);
#ifdef CONFIG_IPU_CLOCK_CONTROL
clk_disable_unprepare(clk->ipu_clk_ptr);
#endif // CONFIG_IPU_CLOCK_CONTROL
/* NOTE: here need not call "clk_disable_unprepare(clk->vcodecbus_clk_ptr)" because it is used by both IPU and VCODEC
process can guarentee it!! */
mutex_unlock(&clk->clk_mutex);
}
+48
View File
@@ -0,0 +1,48 @@
/* Module internals
*
* Copyright (C) 2017 Hisilicon, Inc. All Rights Reserved.
*
* These coded instructions, statements, and computer programs are the
* copyrighted works and confidential proprietary information of
* Hisilicon Inc. and its licensors, and are licensed to the recipient
* under the terms of a separate license agreement. They may be
* adapted and modified by bona fide purchasers under the terms of the
* separate license agreement for internal use, but no adapted or
* modified version may be disclosed or distributed to third parties
* in any manner, medium, or form, in whole or in part, without the
* prior written consent of Hisilicon Inc.
*/
#ifndef _IPU_CLOCK_H
#define _IPU_CLOCK_H
#include <linux/clk.h>
#include <linux/mutex.h>
#define IPU_CLOCK_UNSET (0)
struct ics_clock {
struct clk *ipu_clk_ptr;
struct clk *vcodecbus_clk_ptr;
unsigned int ipu_low;
unsigned int ipu_middle;
unsigned int ipu_high;
unsigned int ipu_low_temperature;
unsigned int vcodecbus_low;
unsigned int vcodecbus_middle;
unsigned int vcodecbus_high;
unsigned int vcodecbus_default;
unsigned int vcodecbus_high2default;
unsigned int start_rate;
unsigned int curr_rate;
unsigned int stop_rate;
struct mutex clk_mutex;
bool lpm3_set_vcodecbus;
};
extern int ipu_clock_init(struct device *dev, struct ics_clock *clk, bool lpm3_set_vcodecbus);
extern int ipu_clock_start(struct ics_clock *clk);
extern void ipu_clock_stop(struct ics_clock *clk);
extern int ipu_clock_set_rate(struct ics_clock *clk, unsigned int new_rate);
extern int ipu_clock_set_start_rate(struct ics_clock *clk, unsigned int new_rate);
#endif
+433
View File
@@ -0,0 +1,433 @@
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/ioctl.h>
#include <linux/io.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/workqueue.h>
#include <linux/errno.h>
#include <asm/uaccess.h>
#include <asm/compiler.h>
#include <mntn_subtype_exception.h>
#include <mntn_public_interface.h>
#include "ipu_mntn.h"
#include "ipu_smmu_drv.h"
#include "cambricon_ipu.h"
struct rdr_exception_info_s ipu_excetption_info[] = {
{
.e_modid = (u32)MODID_NPU_EXC_DEAD,
.e_modid_end = (u32)MODID_NPU_EXC_DEAD,
.e_process_priority = RDR_ERR,
.e_reboot_priority = RDR_REBOOT_NO,
.e_notify_core_mask = RDR_NPU,
.e_reset_core_mask = RDR_NPU,
.e_from_core = RDR_NPU,
.e_reentrant = (u32)RDR_REENTRANT_DISALLOW,
.e_exce_type = NPU_S_EXCEPTION,
.e_exce_subtype = NPU_EXC_DEAD,
.e_upload_flag = (u32)RDR_UPLOAD_YES,
.e_from_module = "NPU",
.e_desc = "NPU_EXC_DEAD",
},
{
.e_modid = (u32)MODID_NPU_EXC_SET_BACK_CLOCK_FAIL,
.e_modid_end = (u32)MODID_NPU_EXC_SET_BACK_CLOCK_FAIL,
.e_process_priority = RDR_ERR,
.e_reboot_priority = RDR_REBOOT_NO,
.e_notify_core_mask = RDR_NPU,
.e_reset_core_mask = RDR_NPU,
.e_from_core = RDR_NPU,
.e_reentrant = (u32)RDR_REENTRANT_DISALLOW,
.e_exce_type = NPU_S_EXCEPTION,
.e_exce_subtype = NPU_SET_BACK_CLOCK_FAIL,
.e_upload_flag = (u32)RDR_UPLOAD_YES,
.e_from_module = "NPU",
.e_desc = "NPU_SET_BACK_CLOCK_FAIL",
},
{
.e_modid = (u32)MODID_NPU_EXC_SET_CLOCK_FAIL,
.e_modid_end = (u32)MODID_NPU_EXC_SET_CLOCK_FAIL,
.e_process_priority = RDR_ERR,
.e_reboot_priority = RDR_REBOOT_NO,
.e_notify_core_mask = RDR_NPU,
.e_reset_core_mask = RDR_NPU,
.e_from_core = RDR_NPU,
.e_reentrant = (u32)RDR_REENTRANT_DISALLOW,
.e_exce_type = NPU_S_EXCEPTION,
.e_exce_subtype = NPU_SET_CLOCK_FAIL,
.e_upload_flag = (u32)RDR_UPLOAD_YES,
.e_from_module = "NPU",
.e_desc = "NPU_SET_CLOCK_FAIL",
},
{
.e_modid = (u32)MODID_NPU_EXC_SET_POWER_UP_FAIL,
.e_modid_end = (u32)MODID_NPU_EXC_SET_POWER_UP_FAIL,
.e_process_priority = RDR_ERR,
.e_reboot_priority = RDR_REBOOT_NO,
.e_notify_core_mask = RDR_NPU,
.e_reset_core_mask = RDR_NPU,
.e_from_core = RDR_NPU,
.e_reentrant = (u32)RDR_REENTRANT_DISALLOW,
.e_exce_type = NPU_S_EXCEPTION,
.e_exce_subtype = NPU_POWER_UP_FAIL,
.e_upload_flag = (u32)RDR_UPLOAD_YES,
.e_from_module = "NPU",
.e_desc = "NPU_POWER_UP_FAIL",
},
{
.e_modid = (u32)MODID_NPU_EXC_SET_POWER_UP_STATUS_FAULT,
.e_modid_end = (u32)MODID_NPU_EXC_SET_POWER_UP_STATUS_FAULT,
.e_process_priority = RDR_ERR,
.e_reboot_priority = RDR_REBOOT_NO,
.e_notify_core_mask = RDR_NPU,
.e_reset_core_mask = RDR_NPU,
.e_from_core = RDR_NPU,
.e_reentrant = (u32)RDR_REENTRANT_DISALLOW,
.e_exce_type = NPU_S_EXCEPTION,
.e_exce_subtype = NPU_POWER_UP_STA_FAULT,
.e_upload_flag = (u32)RDR_UPLOAD_YES,
.e_from_module = "NPU",
.e_desc = "NPU_POWER_UP_STA_FAULT",
},
{
.e_modid = (u32)MODID_NPU_EXC_SET_POWER_DOWN_FAIL,
.e_modid_end = (u32)MODID_NPU_EXC_SET_POWER_DOWN_FAIL,
.e_process_priority = RDR_ERR,
.e_reboot_priority = RDR_REBOOT_NO,
.e_notify_core_mask = RDR_NPU,
.e_reset_core_mask = RDR_NPU,
.e_from_core = RDR_NPU,
.e_reentrant = (u32)RDR_REENTRANT_DISALLOW,
.e_exce_type = NPU_S_EXCEPTION,
.e_exce_subtype = NPU_POWER_DOWN_FAIL,
.e_upload_flag = (u32)RDR_UPLOAD_YES,
.e_from_module = "NPU",
.e_desc = "NPU_POWER_DOWN_FAIL",
},
{
.e_modid = (u32)MODID_NPU_EXC_INTERRUPT_ABNORMAL,
.e_modid_end = (u32)MODID_NPU_EXC_INTERRUPT_ABNORMAL,
.e_process_priority = RDR_ERR,
.e_reboot_priority = RDR_REBOOT_NO,
.e_notify_core_mask = RDR_NPU,
.e_reset_core_mask = RDR_NPU,
.e_from_core = RDR_NPU,
.e_reentrant = (u32)RDR_REENTRANT_DISALLOW,
.e_exce_type = NPU_S_EXCEPTION,
.e_exce_subtype = NPU_INTERRUPT_ABNORMAL,
.e_upload_flag = (u32)RDR_UPLOAD_YES,
.e_from_module = "NPU",
.e_desc = "NPU_INTERRUPT_ABNORMAL",
}
};
struct work_struct ipu_dump_work;
struct workqueue_struct *ipu_mntn_rdr_wq;
struct ipu_mntn_info_s ipu_mntn_info;
struct ipu_reg_info_s ipu_reg_info;
extern struct cambricon_ipu_private *adapter;
/********************************************************************
Description: ipu_mntn_copy_reg_to_bbox
input: char *src_addr, unsigned int* offset, unsigned int len
output: NA
return: void
********************************************************************/
static int ipu_mntn_copy_reg_to_bbox(char *src_addr, unsigned int len)
{
unsigned int temp_offset = 0;
if ((NULL == src_addr) || (0 == len)) {
printk(KERN_ERR"[%s]:IPU_ERROR:Input parameter is error!\n", __func__);
return -EINVAL;
}
temp_offset = ipu_mntn_info.bbox_addr_offset + len;
//ipu_bbox alloc size 64k
if (temp_offset > 0x10000) {
printk(KERN_ERR"[%s]:IPU_ERROR:Copy log to bbox size is error! temp_offset=%d\n", __func__, temp_offset);
temp_offset = 0;
ipu_mntn_info.bbox_addr_offset = 0;
return -ENOMEM ;
}
memcpy(((char*)ipu_mntn_info.rdr_addr + ipu_mntn_info.bbox_addr_offset), src_addr, len);
ipu_mntn_info.bbox_addr_offset = temp_offset;
return 0;
}
/********************************************************************
Description: ipu_mntn_write_adapter_info
input: char *file_path
output: NA
return: void
********************************************************************/
static void ipu_mntn_write_adapter_info(void)
{
char log_buf[IPU_LINE_MAX + 1] = {0};
snprintf(log_buf, IPU_LINE_MAX, "npu_status=%d, ttbr0=%lx, inst_set=%d, offchip{set=%x, base=%x}, last_computed_task=%ld.\r\n",
adapter->ipu_power_up,
adapter->smmu_ttbr0,
adapter->boot_inst_set.boot_inst_recorded_is_config,
adapter->boot_inst_set.access_ddr_addr_is_config,
adapter->boot_inst_set.ipu_access_ddr_addr,
adapter->computed_task_cnt);
ipu_mntn_copy_reg_to_bbox(log_buf, strlen(log_buf));
return;
}
/********************************************************************
Description: ipu_mntn_write_peri_reg_info
input: char *file_path
output: NA
return: void
********************************************************************/
static void ipu_mntn_write_peri_reg_info(void)
{
char log_buf[IPU_LINE_MAX + 1] = {0};
snprintf(log_buf, IPU_LINE_MAX, "peri_stat=%x, ppll_select=%x, power_stat=%x, power_ack=%x, reset_stat=%x, perclken=%x, perstat=%x.\r\n",
ipu_reg_info.peri_reg.peri_stat,
ipu_reg_info.peri_reg.ppll_select,
ipu_reg_info.peri_reg.power_stat,
ipu_reg_info.peri_reg.power_ack,
ipu_reg_info.peri_reg.reset_stat,
ipu_reg_info.peri_reg.perclken0,
ipu_reg_info.peri_reg.perstat0);
ipu_mntn_copy_reg_to_bbox(log_buf, strlen(log_buf));
return;
}
/********************************************************************
Description: ipu_mntn_write_mstr_reg_info
input: char *file_path
output: NA
return: void
********************************************************************/
static void ipu_mntn_write_mstr_reg_info(void)
{
char log_buf[IPU_BUF_LEN_MAX + 1] = {0};
snprintf(log_buf, IPU_BUF_LEN_MAX, "RD_BITMAP=%x, WR_BITMAP=%x, rd_cmd_total_cnt[0-3]={%x, %x, %x}, wr_cmd_total_cnt=%x\n",
ipu_reg_info.mstr_reg.rd_bitmap,
ipu_reg_info.mstr_reg.wr_bitmap,
ipu_reg_info.mstr_reg.rd_cmd_total_cnt0,
ipu_reg_info.mstr_reg.rd_cmd_total_cnt0,
ipu_reg_info.mstr_reg.rd_cmd_total_cnt2,
ipu_reg_info.mstr_reg.wr_cmd_total_cnt);
ipu_mntn_copy_reg_to_bbox(log_buf, strlen(log_buf));
return;
}
/********************************************************************
Description: ipu_mntn_write_reg_log
input: void
output: NA
return: void
********************************************************************/
static void ipu_mntn_write_reg_log(void)
{
switch (ipu_mntn_info.dump_info.modid) {
case MODID_NPU_EXC_DEAD: //lint !e650
ipu_mntn_write_adapter_info();
ipu_mntn_write_peri_reg_info();
ipu_mntn_write_mstr_reg_info();
#ifdef CONFIG_HUAWEI_DSM
ipu_mntn_copy_reg_to_bbox(register_info, strlen(register_info));
#endif
break;
case MODID_NPU_EXC_SET_BACK_CLOCK_FAIL: //lint !e650
case MODID_NPU_EXC_SET_CLOCK_FAIL: //lint !e650
case MODID_NPU_EXC_SET_POWER_UP_FAIL: //lint !e650
case MODID_NPU_EXC_SET_POWER_UP_STATUS_FAULT: //lint !e650
case MODID_NPU_EXC_SET_POWER_DOWN_FAIL: //lint !e650
case MODID_NPU_EXC_INTERRUPT_ABNORMAL: //lint !e650
break;
default:
break;
}
return;
}
/********************************************************************
Description: ipu_mntn_rdr_dump
input: modid: module id
etype:exception type
coreid: core id
pathname: log path
pfn_cb: callback function
output: NA
return: NA
********************************************************************/
static void ipu_mntn_rdr_dump(u32 modid, u32 etype, u64 coreid, char *pathname, pfn_cb_dump_done pfn_cb)
{
if (NULL == pathname) {
printk(KERN_ERR"[%s]:IPU_ERROR:pathname is empty\n", __func__);
return;
}
ipu_mntn_info.dump_info.modid = modid;
ipu_mntn_info.dump_info.coreid = coreid;
ipu_mntn_info.dump_info.pathname = pathname;
ipu_mntn_info.dump_info.cb = pfn_cb;
ipu_mntn_info.bbox_addr_offset = 0;
queue_work(ipu_mntn_rdr_wq, &ipu_dump_work);
return;
}
/********************************************************************
Description: ipu_mntn_rdr_reset
input: modid:module id
etype:exception type
coreid:core id
output: NA
return: NA
********************************************************************/
static void ipu_mntn_rdr_reset(u32 modid, u32 etype, u64 coreid)
{
return;
}
/********************************************************************
Description: ipu_mntn_dump_work
input: struct work_struct *work
output: NA
return: NA
********************************************************************/
static void ipu_mntn_dump_work(struct work_struct *work)
{
ipu_mntn_write_reg_log();
if (ipu_mntn_info.dump_info.cb) {
ipu_mntn_info.dump_info.cb(ipu_mntn_info.dump_info.modid, ipu_mntn_info.dump_info.coreid);
}
return;
}
/********************************************************************
Description: ipu_mntn_register_exception
input: NA
output: NA
return: int
********************************************************************/
static int ipu_mntn_register_exception(void)
{
int ret;
unsigned int size;
unsigned long index;
size = sizeof(ipu_excetption_info)/sizeof(struct rdr_exception_info_s);
for (index = 0; index < size; index++) {
/* error return 0, ok return modid */
ret = rdr_register_exception(&ipu_excetption_info[index]);
if (!ret) {
printk(KERN_ERR"[%s]:IPU_ERROR:rdr_register_exception is failed! index=%ld ret=%d\n", __func__, index, ret);
return -EINTR;
}
}
return 0;
}
/********************************************************************
Description: register ipu dump and reset function
input: NA
output: NA
return: int
********************************************************************/
static int ipu_mntn_register_core(void)
{
int ret;
struct rdr_module_ops_pub s_soc_ops;
s_soc_ops.ops_dump = ipu_mntn_rdr_dump;
s_soc_ops.ops_reset = ipu_mntn_rdr_reset;
/* register ipu core dump and reset function */
ret = rdr_register_module_ops((u64)RDR_NPU, &s_soc_ops, &ipu_mntn_info.ipu_ret_info);
if (ret != 0) {
printk(KERN_ERR"[%s]:IPU_ERROR:rdr_register_module_ops is failed! ret=0x%08x\n", __func__, ret);
}
return ret;
}
/********************************************************************
Description: init ipu addr function
input: NA
output: NA
return: int
********************************************************************/
static int ipu_mntn_addr_map(void)
{
ipu_mntn_info.rdr_addr = hisi_bbox_map((phys_addr_t)ipu_mntn_info.ipu_ret_info.log_addr, ipu_mntn_info.ipu_ret_info.log_len);
if (!ipu_mntn_info.rdr_addr) {
printk(KERN_ERR"[%s]:IPU_ERROR:hisi_bbox_map is failed!\n", __func__);
return -EFAULT;
}
return 0;
}
/********************************************************************
Description: ipu_mntn_rdr_resource_init
input: NA
output: NA
return: int
********************************************************************/
static int ipu_mntn_rdr_resource_init(void)
{
ipu_mntn_rdr_wq = create_singlethread_workqueue("ipu_mntn_rdr_wq");
if (!ipu_mntn_rdr_wq) {
printk(KERN_ERR"[%s]:IPU_ERROR:Create_singlethread_workqueue is failed!\n", __func__);
return -EINTR;
}
INIT_WORK(&ipu_dump_work, ipu_mntn_dump_work);
return 0;
}
/********************************************************************
Description: ipu_mntn_rdr_init
input: void
output: NA
return: int
********************************************************************/
int ipu_mntn_rdr_init(void)
{
int ret;
ret = ipu_mntn_rdr_resource_init();
if (0 != ret) {
printk(KERN_ERR"[%s]:IPU_ERROR:ipu_mntn_rdr_resource_init is faild!ret=%d\n", __func__, ret);
return ret;
}
/* register ics exception */
ret = ipu_mntn_register_exception();
if (0 != ret) {
printk(KERN_ERR"[%s]:IPU_ERROR:ipu_mntn_register_exception is faild!ret=%d\n", __func__, ret);
return ret;
}
/* register ics dump and reset function */
ret = ipu_mntn_register_core();
if (0 != ret) {
printk(KERN_ERR"[%s]:IPU_ERROR:ipu_register_core is failed!ret=%d\n", __func__, ret);
return ret;
}
ret = ipu_mntn_addr_map();
if (0 != ret) {
printk(KERN_ERR"[%s]:IPU_ERROR:ipu_mntn_addr_map is failed!ret=%d\n", __func__, ret);
return ret;
}
return 0;
}
+69
View File
@@ -0,0 +1,69 @@
#ifndef _IPU_MNTN_H_
#define _IPU_MNTN_H_
#include <linux/netlink.h>
#include <linux/sched.h>
#include <net/sock.h>
#include <linux/hisi/rdr_pub.h>
/* AI DRD */
#define IPU_BUF_LEN_MAX (256)
#define IPU_LINE_MAX (128)
enum rdr_ipu_system_error_type {
MODID_NPU_START = HISI_BB_MOD_NPU_START,
MODID_NPU_EXC_DEAD = MODID_NPU_START,
MODID_NPU_EXC_SET_BACK_CLOCK_FAIL,
MODID_NPU_EXC_SET_CLOCK_FAIL,
MODID_NPU_EXC_SET_POWER_UP_FAIL,
MODID_NPU_EXC_SET_POWER_UP_STATUS_FAULT,
MODID_NPU_EXC_SET_POWER_DOWN_FAIL,
MODID_NPU_EXC_INTERRUPT_ABNORMAL,
MODID_NPU_EXC_END = HISI_BB_MOD_NPU_END
};
struct rdr_dump_info_s {
u32 modid;
u64 coreid;
pfn_cb_dump_done cb;
char *pathname;
};
struct ipu_peri_reg_s {
unsigned int peri_stat;
unsigned int ppll_select;
unsigned int power_stat;
unsigned int power_ack;
unsigned int reset_stat;
unsigned int perclken0;
unsigned int perstat0;
};
struct ipu_mstr_reg_s {
unsigned int rd_bitmap;
unsigned int wr_bitmap;
unsigned int rd_cmd_total_cnt0;
unsigned int rd_cmd_total_cnt1;
unsigned int rd_cmd_total_cnt2;
unsigned int wr_cmd_total_cnt;
};
struct ipu_mntn_info_s {
unsigned int ipu_run_status;
unsigned int bbox_addr_offset;
struct rdr_register_module_result ipu_ret_info;
struct rdr_dump_info_s dump_info;
void *rdr_addr;
};
struct ipu_reg_info_s {
struct ipu_peri_reg_s peri_reg;
struct ipu_mstr_reg_s mstr_reg;
};
extern struct workqueue_struct *ipu_mntn_rdr_wq;
extern struct ipu_reg_info_s ipu_reg_info;
extern int ipu_mntn_rdr_init(void);
#endif
File diff suppressed because it is too large Load Diff
+122
View File
@@ -0,0 +1,122 @@
/* Module internals
*
* Copyright (C) 2016 Hisilicon, Inc. All Rights Reserved.
*
* These coded instructions, statements, and computer programs are the
* copyrighted works and confidential proprietary information of
* Hisilicon Inc. and its licensors, and are licensed to the recipient
* under the terms of a separate license agreement. They may be
* adapted and modified by bona fide purchasers under the terms of the
* separate license agreement for internal use, but no adapted or
* modified version may be disclosed or distributed to third parties
* in any manner, medium, or form, in whole or in part, without the
* prior written consent of Hisilicon Inc.
*/
#ifndef _IPU_SMMU_DRV_H
#define _IPU_SMMU_DRV_H
#include <linux/genalloc.h>
#include <linux/iommu.h>
#include <linux/mutex.h>
#include <linux/scatterlist.h>
#include <linux/hisi/hisi_ion.h>
#define IPU_SMMU_ENABLE
#define CAMBRICON_IPU_IRQ
#define IPU_BASE_ADDRESS 0xff400000
#define IPU_SMMU_MSTR_BASE (IPU_BASE_ADDRESS + 0xA0000)
#define IPU_SMMU_COMM_BASE (IPU_BASE_ADDRESS + 0x80000)
#define IPU_SMMU_MSTR_BASE_ES (IPU_BASE_ADDRESS + 0x84000)
#define IPU_SMMU_COMM_BASE_ES (IPU_BASE_ADDRESS + 0x80000)
#define IPU_SMMU_READ_STREAM_NUMBER (3)
#define IPU_SMMU_TAG_COMPARE_CASE_NUMBER (6)
#define IPU_SMMU_TOTAL_STREAM_ID_NUMBER (4)
#ifdef CONFIG_HUAWEI_DSM
#define REGISTER_INFO_MAX_LEN (1024)
extern char register_info[REGISTER_INFO_MAX_LEN];
#endif
#define DEBUG(fmt, ...) printk(KERN_DEBUG "[%s+%d]: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
struct map_format {
unsigned long iova_start;
unsigned long iova_size;
int prot;
};
struct map_data {
int share_fd;
struct map_format format;
};
struct memory_manage_node {
struct list_head head;
struct map_data map;
};
struct smmu_irq_count {
unsigned int mstr_wdata_burst;
unsigned int mstr_wr_va_out_of_128byte;
unsigned int mstr_wr_va_out_of_boundary;
unsigned int mstr_rd_va_out_of_128byte;
unsigned int mstr_rd_va_out_of_boundary;
unsigned int comm_ptw_ns_stat;
unsigned int comm_ptw_invalid_stat;
unsigned int comm_ptw_trans_stat;
unsigned int comm_tlbmiss_stat;
unsigned int comm_ext_stat;
unsigned int comm_permis_stat;
};
struct smmu_statistic {
unsigned int read_stream_cmd_total[IPU_SMMU_READ_STREAM_NUMBER];
unsigned int read_stream_cmd_miss[IPU_SMMU_READ_STREAM_NUMBER];
unsigned int read_stream_data_total[IPU_SMMU_READ_STREAM_NUMBER];
unsigned int read_stream_cmd_miss_valid;
unsigned int read_stream_cmd_miss_pending;
unsigned int read_stream_cmd_hit_valid_not_slide_window;
unsigned int read_stream_cmd_hit_valid_slide_window;
unsigned int read_stream_cmd_hit_pending_not_slide_window;
unsigned int read_stream_cmd_hit_pending_slide_window;
unsigned int read_stream_cmd_latency;
unsigned int write_stream_cmd_total;
unsigned int write_stream_cmd_miss;
unsigned int write_stream_data_total;
unsigned int write_stream_cmd_miss_valid;
unsigned int write_stream_cmd_miss_pending;
unsigned int write_stream_cmd_hit_valid_not_slide_window;
unsigned int write_stream_cmd_hit_valid_slide_window;
unsigned int write_stream_cmd_hit_pending_not_slide_window;
unsigned int write_stream_cmd_hit_pending_slide_window;
unsigned int write_stream_cmd_latency;
struct smmu_irq_count smmu_irq_count;
};
extern struct ion_client* ipu_ion_client;
extern void ipu_smmu_init(unsigned long ttbr0, unsigned long smmu_rw_err_phy_addr, bool port_sel, bool hardware_start);
extern void ipu_smmu_deinit(void);
extern unsigned long ipu_get_smmu_base_phy(struct device *dev);
extern long ipu_smmu_map(struct map_data *map);
extern long ipu_smmu_unmap(struct map_data *map);
extern bool ipu_smmu_interrupt_handler(struct smmu_irq_count *irq_count);
extern void ipu_smmu_reset_statistic(void);
extern void ipu_smmu_record_statistic(struct smmu_statistic *statistic);
extern void ipu_smmu_pte_update(void);
extern bool ipu_smmu_master_get_offset(struct device *dev);
extern bool ipu_smmu_common_get_offset(struct device *dev);
extern void ipu_smmu_override_prefetch_addr(unsigned long reset_va);
extern int ipu_smmu_mngr_init(void);
extern void ipu_smmu_mngr_deinit(void);
extern void ipu_mem_mngr_init(void);
extern void ipu_mem_mngr_deinit(unsigned long *reset_va);
extern void * ipu_mem_mngr_add(struct map_data *map);
extern int ipu_mem_mngr_del(struct map_data *map);
extern int ipu_mem_mngr_check_valid(unsigned int inst_addr);
extern void ipu_mem_mngr_dump(void);
extern void ipu_smmu_dump_strm(void);
#endif
+1 -1
View File
@@ -353,6 +353,6 @@
/*clk media2*/
#define KIRIN970_CLK_GATE_VDECFREQ 0
#define KIRIN970_CLK_GATE_VENCFREQ 1
#define KIRIN970_CLK_GATE_ICSFREQ 2
#endif /* __DT_BINDINGS_CLOCK_KIRIN970_H */