mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-08 11:50:43 +09:00
meson: add timer/cpu_info/cpu_version/mailbox/reg_access/secmon drivers
PD#138714: add base amlogic drivers bc timer/cpu_info/cpu_version/mailbox/reg_access/secmon Change-Id: If45019748dbdc646300ecd67fda2a04f03b7ea52 Signed-off-by: Yun Cai <yun.cai@amlogic.com>
This commit is contained in:
22
MAINTAINERS
22
MAINTAINERS
@@ -13409,3 +13409,25 @@ F: */
|
||||
AMLOGIC Pinmux
|
||||
M: Jianxin Pan <jianxin.pan@amlogic.com>
|
||||
F: drivers/amlogic/pinctrl/*
|
||||
|
||||
AMLOGIC CLOCKSOURCE DRIVER
|
||||
M: Yun Cai <yun.cai@amlogic.com>
|
||||
F: drivers/amlogic/clocksource/
|
||||
|
||||
AMLOGIC CPU INFORMATION DRIVER
|
||||
M: Yun Cai <yun.cai@amlogic.com>
|
||||
F: drivers/amlogic/cpu_info/
|
||||
F: drivers/amlogic/cpu_version/
|
||||
|
||||
AMLOGIC MAILBOX DRIVER
|
||||
M: Yun Cai <yun.cai@amlogic.com>
|
||||
F: drivers/amlogic/mailbox/
|
||||
|
||||
AMLOGIC REGISTER DEBUG DRIVER
|
||||
M: Yun Cai <yun.cai@amlogic.com>
|
||||
F: drivers/amlogic/reg_access/
|
||||
|
||||
AMLOGIC SECURE MONITOR DRIVER
|
||||
M: Yun Cai <yun.cai@amlogic.com>
|
||||
F: drivers/amlogic/secmon/
|
||||
|
||||
|
||||
@@ -130,7 +130,6 @@
|
||||
interrupts = <GIC_PPI 9 0xf04>;
|
||||
};
|
||||
|
||||
|
||||
psci {
|
||||
compatible = "arm,psci";
|
||||
method = "smc";
|
||||
@@ -139,12 +138,14 @@
|
||||
cpu_on = <0xC4000003>;
|
||||
migrate = <0xC4000005>;
|
||||
};
|
||||
|
||||
secmon {
|
||||
compatible = "amlogic, secmon";
|
||||
memory-region = <&secmon_reserved>;
|
||||
in_base_func = <0x82000020>;
|
||||
out_base_func = <0x82000021>;
|
||||
};
|
||||
|
||||
cpu_iomap{
|
||||
compatible = "amlogic, iomap";
|
||||
#address-cells=<2>;
|
||||
@@ -163,7 +164,26 @@
|
||||
|
||||
cpu_version{
|
||||
reg=<0x0 0xc8100220 0x0 0x4>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
cpu_info{
|
||||
compatible = "amlogic, cpuinfo";
|
||||
cpuinfo_cmd = <0x82000044>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
mailbox: mhu@c883c400 {
|
||||
compatible = "amlogic, meson_mhu";
|
||||
reg = <0x0 0xc883c400 0x0 0x4c>, /* MHU registers */
|
||||
<0x0 0xc8013000 0x0 0x800>; /* Payload area */
|
||||
interrupts = <0 209 8>, /* low priority interrupt */
|
||||
<0 210 8>; /* high priority interrupt */
|
||||
#mbox-cells = <1>;
|
||||
mbox-names = "cpu_to_scp_low", "cpu_to_scp_high";
|
||||
mboxes = <&mailbox 0 &mailbox 1>;
|
||||
};
|
||||
|
||||
aobus: aobus@c8100000 {
|
||||
compatible = "simple-bus";
|
||||
reg = <0x0 0xc8100000 0x0 0x100000>;
|
||||
|
||||
@@ -175,7 +175,6 @@
|
||||
interrupts = <GIC_PPI 9 0xf04>;
|
||||
};
|
||||
|
||||
|
||||
psci {
|
||||
compatible = "arm,psci";
|
||||
method = "smc";
|
||||
@@ -184,12 +183,14 @@
|
||||
cpu_on = <0xC4000003>;
|
||||
migrate = <0xC4000005>;
|
||||
};
|
||||
|
||||
secmon {
|
||||
compatible = "amlogic, secmon";
|
||||
memory-region = <&secmon_reserved>;
|
||||
in_base_func = <0x82000020>;
|
||||
out_base_func = <0x82000021>;
|
||||
};
|
||||
|
||||
cpu_iomap{
|
||||
compatible = "amlogic, iomap";
|
||||
#address-cells=<2>;
|
||||
@@ -208,7 +209,26 @@
|
||||
|
||||
cpu_version{
|
||||
reg=<0x0 0xc8100220 0x0 0x4>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
cpu_info{
|
||||
compatible = "amlogic, cpuinfo";
|
||||
cpuinfo_cmd = <0x82000044>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
mailbox: mhu@c883c400 {
|
||||
compatible = "amlogic, meson_mhu";
|
||||
reg = <0x0 0xc883c400 0x0 0x4c>, /* MHU registers */
|
||||
<0x0 0xc8013000 0x0 0x800>; /* Payload area */
|
||||
interrupts = <0 209 8>, /* low priority interrupt */
|
||||
<0 210 8>; /* high priority interrupt */
|
||||
#mbox-cells = <1>;
|
||||
mbox-names = "cpu_to_scp_low", "cpu_to_scp_high";
|
||||
mboxes = <&mailbox 0 &mailbox 1>;
|
||||
};
|
||||
|
||||
aobus: aobus@c8100000 {
|
||||
compatible = "simple-bus";
|
||||
reg = <0x0 0xc8100000 0x0 0x100000>;
|
||||
|
||||
@@ -158,6 +158,14 @@ CONFIG_AMLOGIC_UART=y
|
||||
CONFIG_AMLOGIC_SERIAL_MESON_CONSOLE=y
|
||||
CONFIG_AMLOGIC_IOMAP=y
|
||||
CONFIG_AMLOGIC_PINCTRL=y
|
||||
CONFIG_AMLOGIC_SEC=y
|
||||
CONFIG_AMLOGIC_CPU_VERSION=y
|
||||
CONFIG_AMLOGIC_MESON64_VERSION=y
|
||||
CONFIG_AMLOGIC_CPU_INFO=y
|
||||
CONFIG_AMLOGIC_MHU_MBOX=y
|
||||
CONFIG_AMLOGIC_REG_ACCESS=y
|
||||
CONFIG_AMLOGIC_TIMER=y
|
||||
CONFIG_AMLOGIC_BC_TIMER=y
|
||||
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
|
||||
CONFIG_DEVTMPFS=y
|
||||
CONFIG_DEVTMPFS_MOUNT=y
|
||||
@@ -306,4 +314,3 @@ CONFIG_CRYPTO_USER_API_HASH=y
|
||||
CONFIG_CRYPTO_USER_API_SKCIPHER=y
|
||||
CONFIG_CRC_T10DIF=y
|
||||
CONFIG_CRC7=y
|
||||
|
||||
|
||||
@@ -16,5 +16,18 @@ source "drivers/amlogic/uart/Kconfig"
|
||||
source "drivers/amlogic/iomap/Kconfig"
|
||||
|
||||
source "drivers/amlogic/pinctrl/Kconfig"
|
||||
|
||||
source "drivers/amlogic/secmon/Kconfig"
|
||||
|
||||
source "drivers/amlogic/cpu_version/Kconfig"
|
||||
|
||||
source "drivers/amlogic/cpu_info/Kconfig"
|
||||
|
||||
source "drivers/amlogic/mailbox/Kconfig"
|
||||
|
||||
source "drivers/amlogic/reg_access/Kconfig"
|
||||
|
||||
source "drivers/amlogic/clocksource/Kconfig"
|
||||
|
||||
endmenu
|
||||
endif
|
||||
|
||||
@@ -11,4 +11,18 @@
|
||||
obj-$(CONFIG_AMLOGIC_UART) += uart/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_PINCTRL) += pinctrl/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_IOMAP) += iomap/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_SEC) += secmon/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_CPU_VERSION) += cpu_version/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_CPU_INFO) += cpu_info/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_MHU_MBOX) += mailbox/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_REG_ACCESS) += reg_access/
|
||||
|
||||
obj-$(CONFIG_AMLOGIC_TIMER) += clocksource/
|
||||
|
||||
|
||||
14
drivers/amlogic/clocksource/Kconfig
Normal file
14
drivers/amlogic/clocksource/Kconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
menuconfig AMLOGIC_TIMER
|
||||
bool "Amlogic Meson timer driver"
|
||||
default n
|
||||
help
|
||||
This is the Amlogic Meson driver interface driver
|
||||
if AMLOGIC_TIMER
|
||||
config AMLOGIC_BC_TIMER
|
||||
bool "meson broadcast timer support"
|
||||
def_bool n
|
||||
depends on AMLOGIC_TIMER
|
||||
select CLKSRC_OF if OF
|
||||
help
|
||||
This is a new clocksource driver for amlogic timer
|
||||
endif
|
||||
1
drivers/amlogic/clocksource/Makefile
Normal file
1
drivers/amlogic/clocksource/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_AMLOGIC_BC_TIMER) += meson_bc_timer.o
|
||||
282
drivers/amlogic/clocksource/meson_bc_timer.c
Normal file
282
drivers/amlogic/clocksource/meson_bc_timer.c
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* drivers/amlogic/clocksource/meson_bc_timer.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/stat.h>
|
||||
#include <asm/memory.h>
|
||||
#include <linux/sched_clock.h>
|
||||
#include <linux/of.h>
|
||||
#include <asm/smp_plat.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "meson_bc_timer: " fmt
|
||||
|
||||
/***********************************************************************
|
||||
* System timer
|
||||
**********************************************************************/
|
||||
#define TIMER_E_RESOLUTION_BIT 8
|
||||
#define TIMER_E_ENABLE_BIT 20
|
||||
#define TIMER_E_RESOLUTION_MASK (7UL << TIMER_E_RESOLUTION_BIT)
|
||||
#define TIMER_E_RESOLUTION_SYS 0
|
||||
#define TIMER_E_RESOLUTION_1us 1
|
||||
#define TIMER_E_RESOLUTION_10us 2
|
||||
#define TIMER_E_RESOLUTION_100us 3
|
||||
#define TIMER_E_RESOLUTION_1ms 4
|
||||
|
||||
#define TIMER_DI_RESOLUTION_BIT 6
|
||||
#define TIMER_CH_RESOLUTION_BIT 4
|
||||
#define TIMER_BG_RESOLUTION_BIT 2
|
||||
#define TIMER_AF_RESOLUTION_BIT 0
|
||||
|
||||
#define TIMER_DI_ENABLE_BIT 19
|
||||
#define TIMER_CH_ENABLE_BIT 18
|
||||
#define TIMER_BG_ENABLE_BIT 17
|
||||
#define TIMER_AF_ENABLE_BIT 16
|
||||
|
||||
#define TIMER_DI_MODE_BIT 15
|
||||
#define TIMER_CH_MODE_BIT 14
|
||||
#define TIMER_BG_MODE_BIT 13
|
||||
#define TIMER_AF_MODE_BIT 12
|
||||
|
||||
#define TIMER_RESOLUTION_1us 0
|
||||
#define TIMER_RESOLUTION_10us 1
|
||||
#define TIMER_RESOLUTION_100us 2
|
||||
#define TIMER_RESOLUTION_1ms 3
|
||||
|
||||
void __iomem *timer_ctrl_base;
|
||||
|
||||
static inline void aml_set_reg32_mask(void __iomem *_reg, const uint32_t _mask)
|
||||
{
|
||||
uint32_t _val;
|
||||
|
||||
_val = readl_relaxed(_reg) | _mask;
|
||||
|
||||
writel_relaxed(_val, _reg);
|
||||
}
|
||||
|
||||
static inline void aml_write_reg32(void __iomem *_reg, const uint32_t _value)
|
||||
{
|
||||
writel_relaxed(_value, _reg);
|
||||
}
|
||||
|
||||
static inline void aml_clr_reg32_mask(void __iomem *_reg, const uint32_t _mask)
|
||||
{
|
||||
writel_relaxed((readl_relaxed(_reg) & (~(_mask))), _reg);
|
||||
}
|
||||
|
||||
static inline void
|
||||
aml_set_reg32_bits(void __iomem *_reg, const uint32_t _value,
|
||||
const uint32_t _start, const uint32_t _len)
|
||||
{
|
||||
writel_relaxed(((readl_relaxed(_reg) &
|
||||
~(((1L << (_len))-1) << (_start))) |
|
||||
(((_value)&((1L<<(_len))-1)) << (_start))),
|
||||
_reg);
|
||||
}
|
||||
|
||||
/********** Clock Event Device, Timer-ABCD/FGHI *********/
|
||||
|
||||
struct meson_clock {
|
||||
struct irqaction irq;
|
||||
const char *name; /*A,B,C,D,F,G,H,I*/
|
||||
int bit_enable;
|
||||
int bit_mode;
|
||||
int bit_resolution;
|
||||
void __iomem *mux_reg;
|
||||
void __iomem *reg;
|
||||
unsigned int init_flag;
|
||||
};
|
||||
static struct meson_clock bc_clock;
|
||||
static irqreturn_t meson_timer_interrupt(int irq, void *dev_id);
|
||||
static int meson_set_next_event(unsigned long evt,
|
||||
struct clock_event_device *dev);
|
||||
|
||||
static DEFINE_SPINLOCK(time_lock);
|
||||
|
||||
static int meson_set_next_event(unsigned long evt,
|
||||
struct clock_event_device *dev)
|
||||
{
|
||||
struct meson_clock *clk = &bc_clock;
|
||||
/* use a big number to clear previous trigger cleanly */
|
||||
aml_set_reg32_mask(clk->reg, evt & 0xffff);
|
||||
/* then set next event */
|
||||
aml_set_reg32_bits(clk->reg, evt, 0, 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_clkevt_shutdown(struct clock_event_device *dev)
|
||||
{
|
||||
struct meson_clock *clk = &bc_clock;
|
||||
|
||||
spin_lock(&time_lock);
|
||||
/* pr_info("Disable timer %p %s\n",dev,dev->name); */
|
||||
aml_set_reg32_bits(clk->mux_reg, 0, clk->bit_enable, 1);
|
||||
spin_unlock(&time_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_clkevt_set_periodic(struct clock_event_device *dev)
|
||||
{
|
||||
struct meson_clock *clk = &bc_clock;
|
||||
|
||||
spin_lock(&time_lock);
|
||||
aml_set_reg32_bits(clk->mux_reg, 1, clk->bit_mode, 1);
|
||||
aml_set_reg32_bits(clk->mux_reg, 1, clk->bit_enable, 1);
|
||||
/* pr_info("Periodic timer %s!,mux_reg=%x\n",*/
|
||||
/* dev->name,readl_relaxed(clk->mux_reg)); */
|
||||
spin_unlock(&time_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_clkevt_set_oneshot(struct clock_event_device *dev)
|
||||
{
|
||||
struct meson_clock *clk = &bc_clock;
|
||||
|
||||
spin_lock(&time_lock);
|
||||
aml_set_reg32_bits(clk->mux_reg, 0, clk->bit_mode, 1);
|
||||
aml_set_reg32_bits(clk->mux_reg, 1, clk->bit_enable, 1);
|
||||
/* pr_info("One shot timer %s!mux_reg=%x\n",*/
|
||||
/* dev->name,readl_relaxed(clk->mux_reg)); */
|
||||
spin_unlock(&time_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int meson_clkevt_resume(struct clock_event_device *dev)
|
||||
{
|
||||
struct meson_clock *clk = &bc_clock;
|
||||
|
||||
spin_lock(&time_lock);
|
||||
/* pr_info("Resume timer%s\n", dev->name); */
|
||||
aml_set_reg32_bits(clk->mux_reg, 1, clk->bit_enable, 1);
|
||||
spin_unlock(&time_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clock event timer interrupt handler */
|
||||
static irqreturn_t meson_timer_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct clock_event_device *evt = dev_id;
|
||||
|
||||
if (evt == NULL || evt->event_handler == NULL) {
|
||||
WARN_ONCE(evt == NULL || evt->event_handler == NULL,
|
||||
"%p %s %p %d",
|
||||
evt, evt?evt->name:NULL,
|
||||
evt?evt->event_handler:NULL, irq);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
evt->event_handler(evt);
|
||||
return IRQ_HANDLED;
|
||||
|
||||
}
|
||||
|
||||
static struct clock_event_device meson_clockevent = {
|
||||
.cpumask = cpu_all_mask,
|
||||
.set_next_event = meson_set_next_event,
|
||||
.set_state_shutdown = meson_clkevt_shutdown,
|
||||
.set_state_periodic = meson_clkevt_set_periodic,
|
||||
.set_state_oneshot = meson_clkevt_set_oneshot,
|
||||
.tick_resume = meson_clkevt_resume,
|
||||
};
|
||||
|
||||
/*
|
||||
* This sets up the system timers, clock source and clock event.
|
||||
*/
|
||||
int clockevent_init_and_register(struct device_node *np)
|
||||
{
|
||||
struct device_node *timer;
|
||||
struct meson_clock *mclk = &bc_clock;
|
||||
|
||||
timer = np;
|
||||
if (!timer) {
|
||||
pr_info(" * %s missing timer phandle\n",
|
||||
timer->full_name);
|
||||
return -1;
|
||||
}
|
||||
if (of_property_read_string(timer, "timer_name",
|
||||
&meson_clockevent.name))
|
||||
return -1;
|
||||
|
||||
if (of_property_read_u32(timer, "clockevent-rating",
|
||||
&meson_clockevent.rating))
|
||||
return -1;
|
||||
|
||||
if (of_property_read_u32(timer, "clockevent-shift",
|
||||
&meson_clockevent.shift))
|
||||
return -1;
|
||||
|
||||
if (of_property_read_u32(timer, "clockevent-features",
|
||||
&meson_clockevent.features))
|
||||
return -1;
|
||||
|
||||
if (of_property_read_u32(timer, "bit_enable", &mclk->bit_enable))
|
||||
return -1;
|
||||
|
||||
if (of_property_read_u32(timer, "bit_mode", &mclk->bit_mode))
|
||||
return -1;
|
||||
|
||||
if (of_property_read_u32(timer, "bit_resolution",
|
||||
&mclk->bit_resolution))
|
||||
return -1;
|
||||
|
||||
mclk->mux_reg = timer_ctrl_base;
|
||||
mclk->reg = of_iomap(timer, 1);
|
||||
pr_info("mclk->mux_reg =%p,mclk->reg =%p\n", mclk->mux_reg, mclk->reg);
|
||||
mclk->irq.irq = irq_of_parse_and_map(timer, 0);
|
||||
|
||||
aml_set_reg32_mask(mclk->mux_reg,
|
||||
((1 << mclk->bit_mode)
|
||||
|(TIMER_RESOLUTION_1us << mclk->bit_resolution)));
|
||||
|
||||
meson_clockevent.mult = div_sc(1000000, NSEC_PER_SEC, 20);
|
||||
meson_clockevent.max_delta_ns =
|
||||
clockevent_delta2ns(0xfffe, &meson_clockevent);
|
||||
meson_clockevent.min_delta_ns =
|
||||
clockevent_delta2ns(1, &meson_clockevent);
|
||||
mclk->irq.dev_id = &meson_clockevent;
|
||||
mclk->irq.handler = meson_timer_interrupt;
|
||||
mclk->irq.name = meson_clockevent.name;
|
||||
mclk->irq.flags =
|
||||
IRQF_TIMER | IRQF_IRQPOLL|IRQF_TRIGGER_RISING;
|
||||
/* Set up the IRQ handler */
|
||||
meson_clockevent.irq = mclk->irq.irq;
|
||||
clockevents_register_device(&meson_clockevent);
|
||||
setup_irq(mclk->irq.irq, &mclk->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*meson broadcast timer*/
|
||||
int __init meson_timer_init(struct device_node *np)
|
||||
{
|
||||
timer_ctrl_base = of_iomap(np, 0);
|
||||
if (clockevent_init_and_register(np) < 0)
|
||||
pr_err("%s err\n", __func__);
|
||||
|
||||
return 0;
|
||||
}
|
||||
CLOCKSOURCE_OF_DECLARE(meson_timer, "arm, meson-bc-timer", meson_timer_init);
|
||||
6
drivers/amlogic/cpu_info/Kconfig
Normal file
6
drivers/amlogic/cpu_info/Kconfig
Normal file
@@ -0,0 +1,6 @@
|
||||
config AMLOGIC_CPU_INFO
|
||||
bool "Amlogic chipid"
|
||||
default n
|
||||
help
|
||||
say y to enable Amlogic chipid driver.
|
||||
|
||||
1
drivers/amlogic/cpu_info/Makefile
Normal file
1
drivers/amlogic/cpu_info/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_AMLOGIC_CPU_INFO) += cpu_info.o
|
||||
136
drivers/amlogic/cpu_info/cpu_info.c
Normal file
136
drivers/amlogic/cpu_info/cpu_info.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* drivers/amlogic/cpu_info/cpu_info.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/amlogic/iomap.h>
|
||||
#ifndef CONFIG_ARM64
|
||||
#include <asm/opcodes-sec.h>
|
||||
#endif
|
||||
#include <linux/amlogic/secmon.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/amlogic/cpu_version.h>
|
||||
static int cpuinfo_func_id;
|
||||
|
||||
unsigned int system_serial_low0;
|
||||
unsigned int system_serial_low1;
|
||||
unsigned int system_serial_high0;
|
||||
unsigned int system_serial_high1;
|
||||
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "cpuinfo: " fmt
|
||||
struct aml_cpu_info {
|
||||
unsigned int version;
|
||||
u8 chipid[12];
|
||||
unsigned int reserved[103];
|
||||
};
|
||||
static void __iomem *sharemem_output;
|
||||
static struct aml_cpu_info *cpu_info_buf;
|
||||
static noinline int fn_smc(u64 function_id, u64 arg0, u64 arg1,
|
||||
u64 arg2)
|
||||
{
|
||||
register long x0 asm("x0") = function_id;
|
||||
register long x1 asm("x1") = arg0;
|
||||
register long x2 asm("x2") = arg1;
|
||||
register long x3 asm("x3") = arg2;
|
||||
asm volatile(
|
||||
__asmeq("%0", "x0")
|
||||
__asmeq("%1", "x1")
|
||||
__asmeq("%2", "x2")
|
||||
__asmeq("%3", "x3")
|
||||
"smc #0\n"
|
||||
: "+r" (x0)
|
||||
: "r" (x1), "r" (x2), "r" (x3));
|
||||
|
||||
return function_id;
|
||||
}
|
||||
|
||||
static int cpuinfo_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
unsigned int id;
|
||||
unsigned int *p = NULL;
|
||||
unsigned int version =
|
||||
(get_meson_cpu_version(MESON_CPU_VERSION_LVL_MAJOR) << 24) |
|
||||
(get_meson_cpu_version(MESON_CPU_VERSION_LVL_MINOR) << 16) |
|
||||
(get_meson_cpu_version(MESON_CPU_VERSION_LVL_PACK) << 8);
|
||||
|
||||
if (!of_property_read_u32(np, "cpuinfo_cmd", &id))
|
||||
cpuinfo_func_id = id;
|
||||
cpu_info_buf = kzalloc(sizeof(struct aml_cpu_info), GFP_KERNEL);
|
||||
if (!cpu_info_buf) {
|
||||
pr_info("No memory to alloc\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
sharemem_output = get_secmon_sharemem_output_base();
|
||||
if (!sharemem_output) {
|
||||
pr_info("secmon share mem prepare not okay\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
sharemem_mutex_lock();
|
||||
fn_smc(cpuinfo_func_id, 0, 0, 0);
|
||||
memcpy((void *)cpu_info_buf,
|
||||
(const void *)sharemem_output, sizeof(struct aml_cpu_info));
|
||||
sharemem_mutex_unlock();
|
||||
#if 0
|
||||
int i;
|
||||
unsigned int *p = (unsigned int *)(cpu_info_buf->chipid);
|
||||
|
||||
for (i = 0; i < 12; i++)
|
||||
pr_info("cpu_info_buf->chipid[%d]=%x\n",
|
||||
i, cpu_info_buf->chipid[i]);
|
||||
#endif
|
||||
p = (unsigned int *)(cpu_info_buf->chipid);
|
||||
system_serial_low0 = *p;
|
||||
system_serial_low1 = *(p+1);
|
||||
system_serial_high0 = *(p+2);
|
||||
system_serial_high1 = version;
|
||||
|
||||
pr_info("probe done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id cpuinfo_dt_match[] = {
|
||||
{ .compatible = "amlogic, cpuinfo" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver cpuinfo_platform_driver = {
|
||||
.probe = cpuinfo_probe,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "cpuinfo",
|
||||
.of_match_table = cpuinfo_dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init meson_cpuinfo_init(void)
|
||||
{
|
||||
return platform_driver_register(&cpuinfo_platform_driver);
|
||||
}
|
||||
module_init(meson_cpuinfo_init);
|
||||
|
||||
|
||||
18
drivers/amlogic/cpu_version/Kconfig
Normal file
18
drivers/amlogic/cpu_version/Kconfig
Normal file
@@ -0,0 +1,18 @@
|
||||
menuconfig AMLOGIC_CPU_VERSION
|
||||
bool "Amlogic cpu version support"
|
||||
default n
|
||||
help
|
||||
This is the Amlogic CPU version interface driver
|
||||
|
||||
if AMLOGIC_CPU_VERSION
|
||||
|
||||
config AMLOGIC_MESON64_VERSION
|
||||
bool "Amlogic Meson64 cpu version"
|
||||
default n
|
||||
help
|
||||
say y to enable
|
||||
Amlogic gx-X
|
||||
cpu version driver
|
||||
.
|
||||
|
||||
endif
|
||||
1
drivers/amlogic/cpu_version/Makefile
Normal file
1
drivers/amlogic/cpu_version/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_AMLOGIC_MESON64_VERSION) += meson64_cpu.o
|
||||
92
drivers/amlogic/cpu_version/meson64_cpu.c
Normal file
92
drivers/amlogic/cpu_version/meson64_cpu.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* drivers/amlogic/cpu_version/meson64_cpu.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/amlogic/cpu_version.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/io.h>
|
||||
static int meson_cpu_version[MESON_CPU_VERSION_LVL_MAX+1];
|
||||
void __iomem *assist_hw_rev;
|
||||
|
||||
int get_meson_cpu_version(int level)
|
||||
{
|
||||
if (level >= 0 && level <= MESON_CPU_VERSION_LVL_MAX)
|
||||
return meson_cpu_version[level];
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(get_meson_cpu_version);
|
||||
|
||||
/*
|
||||
* detect if a cpu id is big cpu
|
||||
*/
|
||||
int arch_big_cpu(int cpu)
|
||||
{
|
||||
int type;
|
||||
struct device_node *cpu_version;
|
||||
|
||||
cpu_version = of_find_node_by_name(NULL, "cpu_version");
|
||||
if (cpu_version)
|
||||
assist_hw_rev = of_iomap(cpu_version, 0);
|
||||
else
|
||||
return 0;
|
||||
|
||||
type = readl(assist_hw_rev) >> 24;
|
||||
switch (type) {
|
||||
case MESON_CPU_MAJOR_ID_GXM: /* 0 ~ 3 is faster cpu for GXM */
|
||||
if (cpu < 4)
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(arch_big_cpu);
|
||||
|
||||
int __init meson_cpu_version_init(void)
|
||||
{
|
||||
unsigned int ver;
|
||||
struct device_node *cpu_version;
|
||||
|
||||
cpu_version = of_find_node_by_name(NULL, "cpu_version");
|
||||
if (cpu_version)
|
||||
assist_hw_rev = of_iomap(cpu_version, 0);
|
||||
else
|
||||
return 0;
|
||||
|
||||
meson_cpu_version[MESON_CPU_VERSION_LVL_MAJOR] =
|
||||
readl(assist_hw_rev) >> 24;
|
||||
|
||||
ver = (readl(assist_hw_rev) >> 8) & 0xff;
|
||||
|
||||
meson_cpu_version[MESON_CPU_VERSION_LVL_MINOR] = ver;
|
||||
ver = (readl(assist_hw_rev) >> 16) & 0xff;
|
||||
meson_cpu_version[MESON_CPU_VERSION_LVL_PACK] = ver;
|
||||
pr_info("Meson chip version = Rev%X (%X:%X - %X:%X)\n",
|
||||
meson_cpu_version[MESON_CPU_VERSION_LVL_MINOR],
|
||||
meson_cpu_version[MESON_CPU_VERSION_LVL_MAJOR],
|
||||
meson_cpu_version[MESON_CPU_VERSION_LVL_MINOR],
|
||||
meson_cpu_version[MESON_CPU_VERSION_LVL_PACK],
|
||||
meson_cpu_version[MESON_CPU_VERSION_LVL_MISC]
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
early_initcall(meson_cpu_version_init);
|
||||
31
drivers/amlogic/mailbox/Kconfig
Normal file
31
drivers/amlogic/mailbox/Kconfig
Normal file
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# Amlogic mhu mailbox device configuration
|
||||
#
|
||||
|
||||
menu "MESON MHU mailbox Support"
|
||||
|
||||
config AMLOGIC_MHU_MBOX
|
||||
tristate "MESON MHU Mailbox"
|
||||
default n
|
||||
select MAILBOX
|
||||
select ARM_SCPI_PROTOCOL
|
||||
help
|
||||
MESON MHU Mailbox driver.
|
||||
.
|
||||
.
|
||||
.
|
||||
|
||||
config ARM_SCPI_PROTOCOL
|
||||
tristate "ARM System Control and Power Interface (SCPI) Message Protocol"
|
||||
default n
|
||||
help
|
||||
System Control and Power Interface (SCPI) Message Protocol is
|
||||
defined for the purpose of communication between the Application
|
||||
Cores(AP) and the System Control Processor(SCP). The MHU peripheral
|
||||
provides a mechanism for inter-processor communication between SCP
|
||||
and AP.
|
||||
|
||||
This protocol library provides interface for all the client drivers
|
||||
making use of the features offered by the SCP.
|
||||
|
||||
endmenu
|
||||
2
drivers/amlogic/mailbox/Makefile
Normal file
2
drivers/amlogic/mailbox/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
obj-$(CONFIG_AMLOGIC_MHU_MBOX) += meson_mhu.o
|
||||
obj-$(CONFIG_ARM_SCPI_PROTOCOL) += scpi_protocol.o
|
||||
304
drivers/amlogic/mailbox/meson_mhu.c
Normal file
304
drivers/amlogic/mailbox/meson_mhu.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* drivers/amlogic/mailbox/meson_mhu.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mailbox_controller.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "meson_mhu.h"
|
||||
|
||||
struct device *the_scpi_device;
|
||||
|
||||
#define DRIVER_NAME "meson_mhu"
|
||||
|
||||
/*
|
||||
* +--------------------+-------+---------------+
|
||||
* | Hardware Register | Offset| Driver View |
|
||||
* +--------------------+-------+---------------+
|
||||
* | SCP_INTR_L_STAT | 0x014 | RX_STATUS(L) |
|
||||
* | SCP_INTR_L_SET | 0x010 | RX_SET(L) |
|
||||
* | SCP_INTR_L_CLEAR | 0x018 | RX_CLEAR(L) |
|
||||
* +--------------------+-------+---------------+
|
||||
* | SCP_INTR_H_STAT | 0x020 | RX_STATUS(H) |
|
||||
* | SCP_INTR_H_SET | 0x01c | RX_SET(H) |
|
||||
* | SCP_INTR_H_CLEAR | 0x024 | RX_CLEAR(H) |
|
||||
* +--------------------+-------+---------------+
|
||||
* | CPU_INTR_L_STAT | 0x038 | TX_STATUS(L) |
|
||||
* | CPU_INTR_L_SET | 0x034 | TX_SET(L) |
|
||||
* | CPU_INTR_L_CLEAR | 0x03c | TX_CLEAR(L) |
|
||||
* +--------------------+-------+---------------+
|
||||
* | CPU_INTR_H_STAT | 0x044 | TX_STATUS(H) |
|
||||
* | CPU_INTR_H_SET | 0x040 | TX_SET(H) |
|
||||
* | CPU_INTR_H_CLEAR | 0x048 | TX_CLEAR(H) |
|
||||
* +--------------------+-------+---------------+
|
||||
*/
|
||||
#define RX_OFFSET(chan) (0x10 + (idx) * 0xc)
|
||||
#define RX_STATUS(chan) (RX_OFFSET(chan) + 0x4)
|
||||
#define RX_SET(chan) RX_OFFSET(chan)
|
||||
#define RX_CLEAR(chan) (RX_OFFSET(chan) + 0x8)
|
||||
|
||||
#define TX_OFFSET(chan) (0x34 + (idx) * 0xc)
|
||||
#define TX_STATUS(chan) (TX_OFFSET(chan) + 0x4)
|
||||
#define TX_SET(chan) TX_OFFSET(chan)
|
||||
#define TX_CLEAR(chan) (TX_OFFSET(chan) + 0x8)
|
||||
|
||||
/*
|
||||
* +---------------+-------+----------------+
|
||||
* | Payload | Offset| Driver View |
|
||||
* +---------------+-------+----------------+
|
||||
* | SCP->AP Low | 0x000 | RX_PAYLOAD(L) |
|
||||
* | SCP->AP High | 0x400 | RX_PAYLOAD(H) |
|
||||
* +---------------+-------+----------------+
|
||||
* | AP->SCP Low | 0x200 | TX_PAYLOAD(H) |
|
||||
* | AP->SCP High | 0x600 | TX_PAYLOAD(H) |
|
||||
* +---------------+-------+----------------+
|
||||
*/
|
||||
#define PAYLOAD_MAX_SIZE 0x200
|
||||
#define PAYLOAD_OFFSET 0x400
|
||||
#define RX_PAYLOAD(chan) ((chan) * PAYLOAD_OFFSET)
|
||||
#define TX_PAYLOAD(chan) ((chan) * PAYLOAD_OFFSET + PAYLOAD_MAX_SIZE)
|
||||
|
||||
struct mhu_chan {
|
||||
int index;
|
||||
int rx_irq;
|
||||
struct mhu_ctlr *ctlr;
|
||||
struct mhu_data_buf *data;
|
||||
};
|
||||
|
||||
struct mhu_ctlr {
|
||||
struct device *dev;
|
||||
void __iomem *mbox_base;
|
||||
void __iomem *payload_base;
|
||||
struct mbox_controller mbox_con;
|
||||
struct mhu_chan channels[CHANNEL_MAX];
|
||||
};
|
||||
|
||||
static irqreturn_t mbox_handler(int irq, void *p)
|
||||
{
|
||||
struct mbox_chan *link = (struct mbox_chan *)p;
|
||||
struct mhu_chan *chan = link->con_priv;
|
||||
struct mhu_ctlr *ctlr = chan->ctlr;
|
||||
void __iomem *mbox_base = ctlr->mbox_base;
|
||||
void __iomem *payload = ctlr->payload_base;
|
||||
int idx = chan->index;
|
||||
struct mhu_data_buf *data;
|
||||
unsigned int *pp;
|
||||
u32 status = readl(mbox_base + RX_STATUS(idx));
|
||||
|
||||
if (status && irq == chan->rx_irq) {
|
||||
data = chan->data;
|
||||
pp = (unsigned int *)data->rx_buf;
|
||||
if (!data)
|
||||
return IRQ_NONE; /* spurious */
|
||||
if (data->rx_buf)
|
||||
memcpy(data->rx_buf, payload + RX_PAYLOAD(idx),
|
||||
data->rx_size);
|
||||
chan->data = NULL;
|
||||
mbox_chan_received_data(link, data);
|
||||
writel(~0, mbox_base + RX_CLEAR(idx));
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int mhu_send_data(struct mbox_chan *link, void *msg)
|
||||
{
|
||||
struct mhu_chan *chan = link->con_priv;
|
||||
struct mhu_ctlr *ctlr = chan->ctlr;
|
||||
void __iomem *mbox_base = ctlr->mbox_base;
|
||||
void __iomem *payload = ctlr->payload_base;
|
||||
struct mhu_data_buf *data = (struct mhu_data_buf *)msg;
|
||||
int idx = chan->index;
|
||||
|
||||
if (!data)
|
||||
return -EINVAL;
|
||||
|
||||
chan->data = data;
|
||||
if (data->tx_buf)
|
||||
memcpy(payload + TX_PAYLOAD(idx), data->tx_buf, data->tx_size);
|
||||
writel(data->cmd, mbox_base + TX_SET(idx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mhu_startup(struct mbox_chan *link)
|
||||
{
|
||||
struct mhu_chan *chan = link->con_priv;
|
||||
int err, mbox_irq = chan->rx_irq;
|
||||
|
||||
err = request_threaded_irq(mbox_irq, mbox_handler, NULL, IRQF_ONESHOT,
|
||||
DRIVER_NAME, link);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void mhu_shutdown(struct mbox_chan *link)
|
||||
{
|
||||
struct mhu_chan *chan = link->con_priv;
|
||||
|
||||
chan->data = NULL;
|
||||
free_irq(chan->rx_irq, link);
|
||||
}
|
||||
|
||||
static bool mhu_last_tx_done(struct mbox_chan *link)
|
||||
{
|
||||
struct mhu_chan *chan = link->con_priv;
|
||||
struct mhu_ctlr *ctlr = chan->ctlr;
|
||||
void __iomem *mbox_base = ctlr->mbox_base;
|
||||
int idx = chan->index;
|
||||
|
||||
return !readl(mbox_base + TX_STATUS(idx));
|
||||
}
|
||||
|
||||
static struct mbox_chan_ops mhu_ops = {
|
||||
.send_data = mhu_send_data,
|
||||
.startup = mhu_startup,
|
||||
.shutdown = mhu_shutdown,
|
||||
.last_tx_done = mhu_last_tx_done,
|
||||
};
|
||||
|
||||
static int mhu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mhu_ctlr *ctlr;
|
||||
struct mhu_chan *chan;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mbox_chan *l;
|
||||
struct resource *res;
|
||||
int idx;
|
||||
static const char * const channel_names[] = {
|
||||
CHANNEL_LOW_PRIORITY,
|
||||
CHANNEL_HIGH_PRIORITY
|
||||
};
|
||||
|
||||
ctlr = devm_kzalloc(dev, sizeof(*ctlr), GFP_KERNEL);
|
||||
if (!ctlr)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "failed to get mailbox memory resource\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ctlr->mbox_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(ctlr->mbox_base))
|
||||
return PTR_ERR(ctlr->mbox_base);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
if (!res) {
|
||||
dev_err(dev, "failed to get payload memory resource\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ctlr->payload_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(ctlr->payload_base))
|
||||
return PTR_ERR(ctlr->payload_base);
|
||||
|
||||
ctlr->dev = dev;
|
||||
platform_set_drvdata(pdev, ctlr);
|
||||
|
||||
l = devm_kzalloc(dev, sizeof(*l) * CHANNEL_MAX, GFP_KERNEL);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
ctlr->mbox_con.chans = l;
|
||||
ctlr->mbox_con.num_chans = CHANNEL_MAX;
|
||||
ctlr->mbox_con.txdone_irq = true;
|
||||
ctlr->mbox_con.ops = &mhu_ops;
|
||||
ctlr->mbox_con.dev = dev;
|
||||
|
||||
for (idx = 0; idx < CHANNEL_MAX; idx++) {
|
||||
chan = &ctlr->channels[idx];
|
||||
chan->index = idx;
|
||||
chan->ctlr = ctlr;
|
||||
chan->rx_irq = platform_get_irq(pdev, idx);
|
||||
|
||||
if (chan->rx_irq < 0) {
|
||||
dev_err(dev, "failed to get interrupt for %s\n",
|
||||
channel_names[idx]);
|
||||
return -ENXIO;
|
||||
}
|
||||
l[idx].con_priv = chan;
|
||||
}
|
||||
|
||||
if (mbox_controller_register(&ctlr->mbox_con)) {
|
||||
dev_err(dev, "failed to register mailbox controller\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
the_scpi_device = dev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mhu_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mhu_ctlr *ctlr = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
mbox_controller_unregister(&ctlr->mbox_con);
|
||||
devm_kfree(dev, ctlr->mbox_con.chans);
|
||||
|
||||
devm_iounmap(dev, ctlr->payload_base);
|
||||
devm_iounmap(dev, ctlr->mbox_base);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
devm_kfree(dev, ctlr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id mhu_of_match[] = {
|
||||
{ .compatible = "amlogic, meson_mhu" },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver mhu_driver = {
|
||||
.probe = mhu_probe,
|
||||
.remove = mhu_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = mhu_of_match,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init mhu_init(void)
|
||||
{
|
||||
return platform_driver_register(&mhu_driver);
|
||||
}
|
||||
core_initcall(mhu_init);
|
||||
|
||||
static void __exit mhu_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&mhu_driver);
|
||||
}
|
||||
module_exit(mhu_exit);
|
||||
|
||||
MODULE_AUTHOR("yan wang <yan.wang@amlogic.com>");
|
||||
MODULE_DESCRIPTION("MESON MHU mailbox driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
33
drivers/amlogic/mailbox/meson_mhu.h
Normal file
33
drivers/amlogic/mailbox/meson_mhu.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* drivers/amlogic/mailbox/meson_mhu.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#define CONTROLLER_NAME "mhu_ctlr"
|
||||
|
||||
#define CHANNEL_MAX 2
|
||||
#define CHANNEL_LOW_PRIORITY "cpu_to_scp_low"
|
||||
#define CHANNEL_HIGH_PRIORITY "cpu_to_scp_high"
|
||||
|
||||
struct mhu_data_buf {
|
||||
u32 cmd;
|
||||
int tx_size;
|
||||
void *tx_buf;
|
||||
int rx_size;
|
||||
void *rx_buf;
|
||||
void *cl_data;
|
||||
};
|
||||
|
||||
extern struct device *the_scpi_device;
|
||||
428
drivers/amlogic/mailbox/scpi_protocol.c
Normal file
428
drivers/amlogic/mailbox/scpi_protocol.c
Normal file
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* drivers/amlogic/mailbox/scpi_protocol.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/mailbox_client.h>
|
||||
#include <linux/amlogic/scpi_protocol.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "meson_mhu.h"
|
||||
|
||||
|
||||
#define CMD_ID_SHIFT 0
|
||||
#define CMD_ID_MASK 0xff
|
||||
#define CMD_SENDER_ID_SHIFT 8
|
||||
#define CMD_SENDER_ID_MASK 0xff
|
||||
#define CMD_DATA_SIZE_SHIFT 20
|
||||
#define CMD_DATA_SIZE_MASK 0x1ff
|
||||
#define PACK_SCPI_CMD(cmd, sender, txsz) \
|
||||
((((cmd) & CMD_ID_MASK) << CMD_ID_SHIFT) | \
|
||||
(((sender) & CMD_SENDER_ID_MASK) << CMD_SENDER_ID_SHIFT) | \
|
||||
(((txsz) & CMD_DATA_SIZE_MASK) << CMD_DATA_SIZE_SHIFT))
|
||||
|
||||
#define MAX_DVFS_DOMAINS 3
|
||||
#define MAX_DVFS_OPPS 16
|
||||
#define DVFS_LATENCY(hdr) ((hdr) >> 16)
|
||||
#define DVFS_OPP_COUNT(hdr) (((hdr) >> 8) & 0xff)
|
||||
|
||||
enum scpi_error_codes {
|
||||
SCPI_SUCCESS = 0, /* Success */
|
||||
SCPI_ERR_PARAM = 1, /* Invalid parameter(s) */
|
||||
SCPI_ERR_ALIGN = 2, /* Invalid alignment */
|
||||
SCPI_ERR_SIZE = 3, /* Invalid size */
|
||||
SCPI_ERR_HANDLER = 4, /* Invalid handler/callback */
|
||||
SCPI_ERR_ACCESS = 5, /* Invalid access/permission denied */
|
||||
SCPI_ERR_RANGE = 6, /* Value out of range */
|
||||
SCPI_ERR_TIMEOUT = 7, /* Timeout has occurred */
|
||||
SCPI_ERR_NOMEM = 8, /* Invalid memory area or pointer */
|
||||
SCPI_ERR_PWRSTATE = 9, /* Invalid power state */
|
||||
SCPI_ERR_SUPPORT = 10, /* Not supported or disabled */
|
||||
SCPI_ERR_DEVICE = 11, /* Device error */
|
||||
SCPI_ERR_MAX
|
||||
};
|
||||
|
||||
|
||||
struct scpi_data_buf {
|
||||
int client_id;
|
||||
struct mhu_data_buf *data;
|
||||
struct completion complete;
|
||||
};
|
||||
|
||||
static int high_priority_cmds[] = {
|
||||
SCPI_CMD_GET_CSS_PWR_STATE,
|
||||
SCPI_CMD_CFG_PWR_STATE_STAT,
|
||||
SCPI_CMD_GET_PWR_STATE_STAT,
|
||||
SCPI_CMD_SET_DVFS,
|
||||
SCPI_CMD_GET_DVFS,
|
||||
SCPI_CMD_SET_RTC,
|
||||
SCPI_CMD_GET_RTC,
|
||||
SCPI_CMD_SET_CLOCK_INDEX,
|
||||
SCPI_CMD_SET_CLOCK_VALUE,
|
||||
SCPI_CMD_GET_CLOCK_VALUE,
|
||||
SCPI_CMD_SET_PSU,
|
||||
SCPI_CMD_GET_PSU,
|
||||
SCPI_CMD_SENSOR_CFG_PERIODIC,
|
||||
SCPI_CMD_SENSOR_CFG_BOUNDS,
|
||||
};
|
||||
|
||||
static struct scpi_dvfs_info *scpi_opps[MAX_DVFS_DOMAINS];
|
||||
|
||||
static int scpi_linux_errmap[SCPI_ERR_MAX] = {
|
||||
0, -EINVAL, -ENOEXEC, -EMSGSIZE,
|
||||
-EINVAL, -EACCES, -ERANGE, -ETIMEDOUT,
|
||||
-ENOMEM, -EINVAL, -EOPNOTSUPP, -EIO,
|
||||
};
|
||||
|
||||
static inline int scpi_to_linux_errno(int errno)
|
||||
{
|
||||
if (errno >= SCPI_SUCCESS && errno < SCPI_ERR_MAX)
|
||||
return scpi_linux_errmap[errno];
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static bool high_priority_chan_supported(int cmd)
|
||||
{
|
||||
int idx;
|
||||
|
||||
for (idx = 0; idx < ARRAY_SIZE(high_priority_cmds); idx++)
|
||||
if (cmd == high_priority_cmds[idx])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void scpi_rx_callback(struct mbox_client *cl, void *msg)
|
||||
{
|
||||
struct mhu_data_buf *data = (struct mhu_data_buf *)msg;
|
||||
struct scpi_data_buf *scpi_buf = data->cl_data;
|
||||
|
||||
complete(&scpi_buf->complete);
|
||||
}
|
||||
|
||||
static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, bool high_priority)
|
||||
{
|
||||
struct mbox_chan *chan;
|
||||
struct mbox_client cl = {0};
|
||||
struct mhu_data_buf *data = scpi_buf->data;
|
||||
u32 status;
|
||||
|
||||
cl.dev = the_scpi_device;
|
||||
cl.rx_callback = scpi_rx_callback;
|
||||
|
||||
chan = mbox_request_channel(&cl, high_priority);
|
||||
if (IS_ERR(chan))
|
||||
return PTR_ERR(chan);
|
||||
|
||||
init_completion(&scpi_buf->complete);
|
||||
if (mbox_send_message(chan, (void *)data) < 0) {
|
||||
status = SCPI_ERR_TIMEOUT;
|
||||
goto free_channel;
|
||||
}
|
||||
|
||||
wait_for_completion(&scpi_buf->complete);
|
||||
status = *(u32 *)(data->rx_buf); /* read first word */
|
||||
|
||||
free_channel:
|
||||
mbox_free_channel(chan);
|
||||
|
||||
return scpi_to_linux_errno(status);
|
||||
}
|
||||
|
||||
#define SCPI_SETUP_DBUF(scpi_buf, mhu_buf, _client_id,\
|
||||
_cmd, _tx_buf, _rx_buf) \
|
||||
do { \
|
||||
struct mhu_data_buf *pdata = &mhu_buf; \
|
||||
pdata->cmd = _cmd; \
|
||||
pdata->tx_buf = &_tx_buf; \
|
||||
pdata->tx_size = sizeof(_tx_buf); \
|
||||
pdata->rx_buf = &_rx_buf; \
|
||||
pdata->rx_size = sizeof(_rx_buf); \
|
||||
scpi_buf.client_id = _client_id; \
|
||||
scpi_buf.data = pdata; \
|
||||
} while (0)
|
||||
|
||||
#define SCPI_SETUP_DBUF_SIZE(scpi_buf, mhu_buf, _client_id,\
|
||||
_cmd, _tx_buf, _tx_size, _rx_buf, _rx_size) \
|
||||
do { \
|
||||
struct mhu_data_buf *pdata = &mhu_buf; \
|
||||
pdata->cmd = _cmd; \
|
||||
pdata->tx_buf = _tx_buf; \
|
||||
pdata->tx_size = _tx_size; \
|
||||
pdata->rx_buf = _rx_buf; \
|
||||
pdata->rx_size = _rx_size; \
|
||||
scpi_buf.client_id = _client_id; \
|
||||
scpi_buf.data = pdata; \
|
||||
} while (0)
|
||||
|
||||
static int scpi_execute_cmd(struct scpi_data_buf *scpi_buf)
|
||||
{
|
||||
struct mhu_data_buf *data;
|
||||
bool high_priority;
|
||||
|
||||
if (!scpi_buf || !scpi_buf->data)
|
||||
return -EINVAL;
|
||||
data = scpi_buf->data;
|
||||
high_priority = high_priority_chan_supported(data->cmd);
|
||||
data->cmd = PACK_SCPI_CMD(data->cmd, scpi_buf->client_id,
|
||||
data->tx_size);
|
||||
data->cl_data = scpi_buf;
|
||||
|
||||
return send_scpi_cmd(scpi_buf, high_priority);
|
||||
}
|
||||
|
||||
unsigned long scpi_clk_get_val(u16 clk_id)
|
||||
{
|
||||
struct scpi_data_buf sdata;
|
||||
struct mhu_data_buf mdata;
|
||||
struct __packed {
|
||||
u32 status;
|
||||
u32 clk_rate;
|
||||
} buf;
|
||||
|
||||
SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_CLOCKS,
|
||||
SCPI_CMD_GET_CLOCK_VALUE, clk_id, buf);
|
||||
if (scpi_execute_cmd(&sdata))
|
||||
return 0;
|
||||
|
||||
return buf.clk_rate;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scpi_clk_get_val);
|
||||
|
||||
int scpi_clk_set_val(u16 clk_id, unsigned long rate)
|
||||
{
|
||||
struct scpi_data_buf sdata;
|
||||
struct mhu_data_buf mdata;
|
||||
int stat;
|
||||
struct __packed {
|
||||
u32 clk_rate;
|
||||
u16 clk_id;
|
||||
} buf;
|
||||
|
||||
buf.clk_rate = (u32)rate;
|
||||
buf.clk_id = clk_id;
|
||||
|
||||
SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_CLOCKS,
|
||||
SCPI_CMD_SET_CLOCK_VALUE, buf, stat);
|
||||
return scpi_execute_cmd(&sdata);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scpi_clk_set_val);
|
||||
|
||||
struct scpi_dvfs_info *scpi_dvfs_get_opps(u8 domain)
|
||||
{
|
||||
struct scpi_data_buf sdata;
|
||||
struct mhu_data_buf mdata;
|
||||
struct __packed {
|
||||
u32 status;
|
||||
u32 header;
|
||||
struct scpi_opp_entry opp[MAX_DVFS_OPPS];
|
||||
} buf;
|
||||
struct scpi_dvfs_info *opps;
|
||||
size_t opps_sz;
|
||||
int count, ret;
|
||||
|
||||
if (domain >= MAX_DVFS_DOMAINS)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (scpi_opps[domain]) /* data already populated */
|
||||
return scpi_opps[domain];
|
||||
|
||||
SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DVFS,
|
||||
SCPI_CMD_GET_DVFS_INFO, domain, buf);
|
||||
ret = scpi_execute_cmd(&sdata);
|
||||
if (ret)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
opps = kmalloc(sizeof(*opps), GFP_KERNEL);
|
||||
if (!opps)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
count = DVFS_OPP_COUNT(buf.header);
|
||||
opps_sz = count * sizeof(*(opps->opp));
|
||||
|
||||
opps->count = count;
|
||||
opps->latency = DVFS_LATENCY(buf.header);
|
||||
opps->opp = kmalloc(opps_sz, GFP_KERNEL);
|
||||
if (!opps->opp) {
|
||||
kfree(opps);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
memcpy(opps->opp, &buf.opp[0], opps_sz);
|
||||
scpi_opps[domain] = opps;
|
||||
|
||||
return opps;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scpi_dvfs_get_opps);
|
||||
|
||||
int scpi_dvfs_get_idx(u8 domain)
|
||||
{
|
||||
struct scpi_data_buf sdata;
|
||||
struct mhu_data_buf mdata;
|
||||
struct __packed {
|
||||
u32 status;
|
||||
u8 dvfs_idx;
|
||||
} buf;
|
||||
int ret;
|
||||
|
||||
if (domain >= MAX_DVFS_DOMAINS)
|
||||
return -EINVAL;
|
||||
|
||||
SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DVFS,
|
||||
SCPI_CMD_GET_DVFS, domain, buf);
|
||||
ret = scpi_execute_cmd(&sdata);
|
||||
|
||||
if (!ret)
|
||||
ret = buf.dvfs_idx;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scpi_dvfs_get_idx);
|
||||
|
||||
int scpi_dvfs_set_idx(u8 domain, u8 idx)
|
||||
{
|
||||
struct scpi_data_buf sdata;
|
||||
struct mhu_data_buf mdata;
|
||||
struct __packed {
|
||||
u8 dvfs_domain;
|
||||
u8 dvfs_idx;
|
||||
} buf;
|
||||
int stat;
|
||||
|
||||
buf.dvfs_idx = idx;
|
||||
buf.dvfs_domain = domain;
|
||||
|
||||
if (domain >= MAX_DVFS_DOMAINS)
|
||||
return -EINVAL;
|
||||
|
||||
SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DVFS,
|
||||
SCPI_CMD_SET_DVFS, buf, stat);
|
||||
return scpi_execute_cmd(&sdata);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scpi_dvfs_set_idx);
|
||||
|
||||
int scpi_get_sensor(char *name)
|
||||
{
|
||||
struct scpi_data_buf sdata;
|
||||
struct mhu_data_buf mdata;
|
||||
struct __packed {
|
||||
u32 status;
|
||||
u16 sensors;
|
||||
} cap_buf;
|
||||
struct __packed {
|
||||
u32 status;
|
||||
u16 sensor;
|
||||
u8 class;
|
||||
u8 trigger;
|
||||
char name[20];
|
||||
} info_buf;
|
||||
int ret;
|
||||
u16 sensor_id;
|
||||
|
||||
/* This should be handled by a generic macro */
|
||||
do {
|
||||
struct mhu_data_buf *pdata = &mdata;
|
||||
|
||||
pdata->cmd = SCPI_CMD_SENSOR_CAPABILITIES;
|
||||
pdata->tx_size = 0;
|
||||
pdata->rx_buf = &cap_buf;
|
||||
pdata->rx_size = sizeof(cap_buf);
|
||||
sdata.client_id = SCPI_CL_THERMAL;
|
||||
sdata.data = pdata;
|
||||
} while (0);
|
||||
ret = scpi_execute_cmd(&sdata);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = -ENODEV;
|
||||
for (sensor_id = 0; sensor_id < cap_buf.sensors; sensor_id++) {
|
||||
SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_THERMAL,
|
||||
SCPI_CMD_SENSOR_INFO, sensor_id, info_buf);
|
||||
ret = scpi_execute_cmd(&sdata);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (!strcmp(name, info_buf.name)) {
|
||||
ret = sensor_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scpi_get_sensor);
|
||||
|
||||
int scpi_get_sensor_value(u16 sensor, u32 *val)
|
||||
{
|
||||
struct scpi_data_buf sdata;
|
||||
struct mhu_data_buf mdata;
|
||||
struct __packed {
|
||||
u32 status;
|
||||
u32 val;
|
||||
} buf;
|
||||
int ret;
|
||||
|
||||
SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_THERMAL, SCPI_CMD_SENSOR_VALUE,
|
||||
sensor, buf);
|
||||
ret = scpi_execute_cmd(&sdata);
|
||||
if (ret == 0)
|
||||
*val = buf.val;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scpi_get_sensor_value);
|
||||
|
||||
/****Send fail when data size > 0x1fd. ***
|
||||
* Because of USER_LOW_TASK_SHARE_MEM_BASE ***
|
||||
* size limitation.
|
||||
* You can call scpi_send_usr_data()
|
||||
* multi-times when your data is bigger
|
||||
* than 0x1fe
|
||||
*/
|
||||
int scpi_send_usr_data(u32 client_id, u32 *val, u32 size)
|
||||
{
|
||||
struct scpi_data_buf sdata;
|
||||
struct mhu_data_buf mdata;
|
||||
struct __packed {
|
||||
u32 status;
|
||||
u32 val;
|
||||
} buf;
|
||||
int ret;
|
||||
|
||||
/*client_id bit map should locates @ 0xff.
|
||||
* bl30 will send client_id via half-Word
|
||||
*/
|
||||
if (client_id & ~0xff)
|
||||
return -E2BIG;
|
||||
|
||||
/*Check size here because of USER_LOW_TASK_SHARE_MEM_BASE
|
||||
* size limitation, and first Word is used as command,
|
||||
* second word is used as tx_size.
|
||||
*/
|
||||
if (size > 0x1fd)
|
||||
return -EPERM;
|
||||
|
||||
SCPI_SETUP_DBUF_SIZE(sdata, mdata, client_id, SCPI_CMD_SET_USR_DATA,
|
||||
val, size, &buf, sizeof(buf));
|
||||
ret = scpi_execute_cmd(&sdata);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(scpi_send_usr_data);
|
||||
|
||||
7
drivers/amlogic/reg_access/Kconfig
Normal file
7
drivers/amlogic/reg_access/Kconfig
Normal file
@@ -0,0 +1,7 @@
|
||||
# Amlogic DEBUG
|
||||
#
|
||||
config AMLOGIC_REG_ACCESS
|
||||
bool "Amlogic register access from userspace support"
|
||||
default n
|
||||
help
|
||||
This is the Amlogic debug sysfs interface driver using debugfs interface
|
||||
1
drivers/amlogic/reg_access/Makefile
Normal file
1
drivers/amlogic/reg_access/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_AMLOGIC_REG_ACCESS) =reg_access.o
|
||||
210
drivers/amlogic/reg_access/reg_access.c
Normal file
210
drivers/amlogic/reg_access/reg_access.c
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
* drivers/amlogic/reg_access/reg_access.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Standard Linux headers */
|
||||
#include <linux/types.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
static struct dentry *debugfs_root;
|
||||
/* amlogic debug device*/
|
||||
struct aml_ddev {
|
||||
unsigned int cached_reg_addr;
|
||||
unsigned int size;
|
||||
int (*debugfs_reg_access)(struct aml_ddev *indio_dev,
|
||||
unsigned int reg, unsigned int writeval,
|
||||
unsigned int *readval);
|
||||
};
|
||||
int aml_reg_access(struct aml_ddev *indio_dev,
|
||||
unsigned int reg, unsigned int writeval,
|
||||
unsigned int *readval)
|
||||
{
|
||||
void __iomem *vaddr;
|
||||
|
||||
reg = round_down(reg, 0x3);
|
||||
|
||||
vaddr = ioremap(reg, 0x4);
|
||||
|
||||
if (readval)
|
||||
*readval = readl(vaddr);
|
||||
else
|
||||
writel(writeval, vaddr);
|
||||
iounmap(vaddr);
|
||||
return 0;
|
||||
}
|
||||
static struct aml_ddev aml_dev;
|
||||
static ssize_t paddr_read_file(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct aml_ddev *indio_dev = file->private_data;
|
||||
char buf[80];
|
||||
unsigned int val = 0;
|
||||
ssize_t len;
|
||||
int ret;
|
||||
|
||||
ret = indio_dev->debugfs_reg_access(indio_dev,
|
||||
indio_dev->cached_reg_addr,
|
||||
0, &val);
|
||||
if (ret)
|
||||
pr_err("%s: read failed\n", __func__);
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "[0x%x] = 0x%X\n",
|
||||
indio_dev->cached_reg_addr, val);
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, len);
|
||||
|
||||
}
|
||||
|
||||
static ssize_t paddr_write_file(struct file *file, const char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct aml_ddev *indio_dev = file->private_data;
|
||||
unsigned int reg, val;
|
||||
char buf[80];
|
||||
int ret;
|
||||
|
||||
count = min_t(size_t, count, (sizeof(buf)-1));
|
||||
if (copy_from_user(buf, userbuf, count))
|
||||
return -EFAULT;
|
||||
|
||||
buf[count] = 0;
|
||||
|
||||
ret = sscanf(buf, "%x %x", ®, &val);
|
||||
|
||||
switch (ret) {
|
||||
case 1:
|
||||
indio_dev->cached_reg_addr = reg;
|
||||
break;
|
||||
case 2:
|
||||
indio_dev->cached_reg_addr = reg;
|
||||
ret = indio_dev->debugfs_reg_access(indio_dev, reg,
|
||||
val, NULL);
|
||||
if (ret) {
|
||||
pr_err("%s: write failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations paddr_file_ops = {
|
||||
.open = simple_open,
|
||||
.read = paddr_read_file,
|
||||
.write = paddr_write_file,
|
||||
};
|
||||
|
||||
|
||||
static ssize_t dump_write_file(struct file *file, const char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct seq_file *s = file->private_data;
|
||||
struct aml_ddev *indio_dev = s->private;
|
||||
unsigned int reg, val;
|
||||
char buf[80];
|
||||
int ret;
|
||||
|
||||
count = min_t(size_t, count, (sizeof(buf)-1));
|
||||
if (copy_from_user(buf, userbuf, count))
|
||||
return -EFAULT;
|
||||
|
||||
buf[count] = 0;
|
||||
|
||||
ret = sscanf(buf, "%x %i", ®, &val);
|
||||
switch (ret) {
|
||||
case 2:
|
||||
indio_dev->cached_reg_addr = reg;
|
||||
indio_dev->size = val;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int dump_show(struct seq_file *s, void *what)
|
||||
{
|
||||
unsigned int i = 0, val;
|
||||
int ret;
|
||||
struct aml_ddev *indio_dev = s->private;
|
||||
|
||||
for (i = 0; i < indio_dev->size ; i++) {
|
||||
ret = indio_dev->debugfs_reg_access(indio_dev,
|
||||
indio_dev->cached_reg_addr,
|
||||
0, &val);
|
||||
if (ret)
|
||||
pr_err("%s: read failed\n", __func__);
|
||||
|
||||
seq_printf(s, "[0x%x] = 0x%X\n",
|
||||
indio_dev->cached_reg_addr, val);
|
||||
indio_dev->cached_reg_addr += 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dump_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, dump_show, inode->i_private);
|
||||
}
|
||||
|
||||
|
||||
static const struct file_operations dump_file_ops = {
|
||||
.open = dump_open,
|
||||
.read = seq_read,
|
||||
.write = dump_write_file,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
static int __init aml_debug_init(void)
|
||||
{
|
||||
debugfs_root = debugfs_create_dir("aml_reg", NULL);
|
||||
if (IS_ERR(debugfs_root) || !debugfs_root) {
|
||||
pr_warn("failed to create debugfs directory\n");
|
||||
debugfs_root = NULL;
|
||||
return -1;
|
||||
}
|
||||
aml_dev.debugfs_reg_access = aml_reg_access;
|
||||
|
||||
debugfs_create_file("paddr", S_IFREG | 0444,
|
||||
debugfs_root, &aml_dev, &paddr_file_ops);
|
||||
debugfs_create_file("dump", S_IFREG | 0444,
|
||||
debugfs_root, &aml_dev, &dump_file_ops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit aml_debug_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
module_init(aml_debug_init);
|
||||
module_exit(aml_debug_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Amlogic debug module");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Xing Xu <xing.xu@amlogic.com>");
|
||||
|
||||
12
drivers/amlogic/secmon/Kconfig
Normal file
12
drivers/amlogic/secmon/Kconfig
Normal file
@@ -0,0 +1,12 @@
|
||||
# Amlogic secure monitor driver
|
||||
|
||||
|
||||
config AMLOGIC_SEC
|
||||
bool "Amlogic secure monitor driver support"
|
||||
default n
|
||||
help
|
||||
This is the Amlogic secure monitor driver
|
||||
this config only ctrl in makefile
|
||||
prepare share memory
|
||||
etc
|
||||
|
||||
1
drivers/amlogic/secmon/Makefile
Normal file
1
drivers/amlogic/secmon/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_AMLOGIC_SEC) += secmon.o
|
||||
154
drivers/amlogic/secmon/secmon.c
Normal file
154
drivers/amlogic/secmon/secmon.c
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* drivers/amlogic/secmon/secmon.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_fdt.h>
|
||||
#include <linux/libfdt_env.h>
|
||||
#include <linux/of_reserved_mem.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/compiler.h>
|
||||
#ifndef CONFIG_ARM64
|
||||
#include <asm/opcodes-sec.h>
|
||||
#endif
|
||||
#undef pr_fmt
|
||||
#define pr_fmt(fmt) "secmon: " fmt
|
||||
|
||||
static void __iomem *sharemem_in_base;
|
||||
static void __iomem *sharemem_out_base;
|
||||
static long phy_in_base;
|
||||
static long phy_out_base;
|
||||
#ifdef CONFIG_ARM64
|
||||
#define IN_SIZE 0x1000
|
||||
#else
|
||||
#define IN_SIZE 0x8000
|
||||
#endif
|
||||
#define OUT_SIZE 0x1000
|
||||
static DEFINE_MUTEX(sharemem_mutex);
|
||||
#ifdef CONFIG_ARM64
|
||||
static long get_sharemem_info(unsigned int function_id)
|
||||
{
|
||||
asm volatile(
|
||||
__asmeq("%0", "x0")
|
||||
"smc #0\n"
|
||||
: "+r" (function_id));
|
||||
|
||||
return function_id;
|
||||
}
|
||||
#else
|
||||
static long get_sharemem_info(unsigned int function_id)
|
||||
{
|
||||
register long r0 asm("r0") = function_id;
|
||||
asm volatile(
|
||||
__asmeq("%0", "r0")
|
||||
__asmeq("%1", "r0")
|
||||
__SMC(0)
|
||||
: "=r" (r0)
|
||||
: "r"(r0));
|
||||
|
||||
return r0;
|
||||
}
|
||||
#endif
|
||||
static int secmon_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
unsigned int id;
|
||||
int ret;
|
||||
|
||||
if (!of_property_read_u32(np, "in_base_func", &id))
|
||||
phy_in_base = get_sharemem_info(id);
|
||||
|
||||
if (!of_property_read_u32(np, "out_base_func", &id))
|
||||
phy_out_base = get_sharemem_info(id);
|
||||
|
||||
ret = of_reserved_mem_device_init(&pdev->dev);
|
||||
if (ret == 0)
|
||||
pr_info("probe done\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id secmon_dt_match[] = {
|
||||
{ .compatible = "amlogic, secmon" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver secmon_platform_driver = {
|
||||
.probe = secmon_probe,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "secmon",
|
||||
.of_match_table = secmon_dt_match,
|
||||
},
|
||||
};
|
||||
|
||||
int __init meson_secmon_init(void)
|
||||
{
|
||||
return platform_driver_register(&secmon_platform_driver);
|
||||
}
|
||||
module_init(meson_secmon_init);
|
||||
|
||||
void sharemem_mutex_lock(void)
|
||||
{
|
||||
mutex_lock(&sharemem_mutex);
|
||||
}
|
||||
void sharemem_mutex_unlock(void)
|
||||
{
|
||||
mutex_unlock(&sharemem_mutex);
|
||||
}
|
||||
|
||||
void __iomem *get_secmon_sharemem_input_base(void)
|
||||
{
|
||||
return sharemem_in_base;
|
||||
}
|
||||
void __iomem *get_secmon_sharemem_output_base(void)
|
||||
{
|
||||
return sharemem_out_base;
|
||||
}
|
||||
|
||||
static int secmon_mem_device_init(struct reserved_mem *rmem, struct device *dev)
|
||||
{
|
||||
sharemem_in_base = ioremap_cache(phy_in_base, IN_SIZE);
|
||||
if (!sharemem_in_base) {
|
||||
pr_info("secmon share mem in buffer remap fail!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
sharemem_out_base = ioremap_cache(phy_out_base, OUT_SIZE);
|
||||
if (!sharemem_out_base) {
|
||||
pr_info("secmon share mem out buffer remap fail!\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
pr_info("share in base: 0x%lx, share out base: 0x%lx\n",
|
||||
(long)sharemem_in_base, (long)sharemem_out_base);
|
||||
return 0;
|
||||
}
|
||||
static const struct reserved_mem_ops rmem_secmon_ops = {
|
||||
.device_init = secmon_mem_device_init,
|
||||
};
|
||||
static int __init secmon_mem_setup(struct reserved_mem *rmem)
|
||||
{
|
||||
rmem->ops = &rmem_secmon_ops;
|
||||
pr_debug("share mem setup\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
RESERVEDMEM_OF_DECLARE(secmonmem, "amlogic, aml_secmon_memory",
|
||||
secmon_mem_setup);
|
||||
132
include/linux/amlogic/cpu_version.h
Normal file
132
include/linux/amlogic/cpu_version.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* include/linux/amlogic/cpu_version.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PLAT_MESON_CPU_H
|
||||
#define __PLAT_MESON_CPU_H
|
||||
|
||||
#define MESON_CPU_MAJOR_ID_GXBB 0x1F
|
||||
#define MESON_CPU_MAJOR_ID_GXTVBB 0x20
|
||||
#define MESON_CPU_MAJOR_ID_GXL 0x21
|
||||
#define MESON_CPU_MAJOR_ID_GXM 0x22
|
||||
#define MESON_CPU_MAJOR_ID_TXL 0x23
|
||||
|
||||
#define MESON_CPU_VERSION_LVL_MAJOR 0
|
||||
#define MESON_CPU_VERSION_LVL_MINOR 1
|
||||
#define MESON_CPU_VERSION_LVL_PACK 2
|
||||
#define MESON_CPU_VERSION_LVL_MISC 3
|
||||
#define MESON_CPU_VERSION_LVL_MAX MESON_CPU_VERSION_LVL_MISC
|
||||
extern unsigned int system_serial_low0;
|
||||
extern unsigned int system_serial_low1;
|
||||
extern unsigned int system_serial_high0;
|
||||
extern unsigned int system_serial_high1;
|
||||
|
||||
int meson_cpu_version_init(void);
|
||||
#ifdef CONFIG_AMLOGIC_CPU_VERSION
|
||||
int get_meson_cpu_version(int level);
|
||||
int arch_big_cpu(int cpu);
|
||||
#else
|
||||
static inline int get_meson_cpu_version(int level)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int arch_big_cpu(int cpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int get_cpu_type(void)
|
||||
{
|
||||
return get_meson_cpu_version(MESON_CPU_VERSION_LVL_MAJOR);
|
||||
}
|
||||
|
||||
static inline u32 get_cpu_package(void)
|
||||
{
|
||||
unsigned int pk;
|
||||
|
||||
pk = get_meson_cpu_version(MESON_CPU_VERSION_LVL_PACK) & 0xF0;
|
||||
return pk;
|
||||
}
|
||||
|
||||
static inline bool package_id_is(unsigned int id)
|
||||
{
|
||||
return get_cpu_package() == id;
|
||||
}
|
||||
|
||||
static inline bool is_meson_gxbb_cpu(void)
|
||||
{
|
||||
return get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB;
|
||||
}
|
||||
|
||||
static inline bool is_meson_gxtvbb_cpu(void)
|
||||
{
|
||||
return get_cpu_type() == MESON_CPU_MAJOR_ID_GXTVBB;
|
||||
}
|
||||
|
||||
static inline bool is_meson_gxbb_package_905(void)
|
||||
{
|
||||
return (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) &&
|
||||
(get_cpu_package() != 0x20);
|
||||
}
|
||||
|
||||
static inline bool is_meson_gxbb_package_905m(void)
|
||||
{
|
||||
return (get_cpu_type() == MESON_CPU_MAJOR_ID_GXBB) &&
|
||||
(get_cpu_package() == 0x20);
|
||||
}
|
||||
|
||||
static inline bool is_meson_gxl_cpu(void)
|
||||
{
|
||||
return get_cpu_type() == MESON_CPU_MAJOR_ID_GXL;
|
||||
}
|
||||
|
||||
static inline bool is_meson_gxl_package_905D(void)
|
||||
{
|
||||
return is_meson_gxl_cpu() && package_id_is(0x0);
|
||||
}
|
||||
static inline bool is_meson_gxl_package_905X(void)
|
||||
{
|
||||
return is_meson_gxl_cpu() && package_id_is(0x80);
|
||||
}
|
||||
|
||||
static inline bool is_meson_gxl_package_905L(void)
|
||||
{
|
||||
return is_meson_gxl_cpu() && package_id_is(0xc0);
|
||||
}
|
||||
|
||||
static inline bool is_meson_gxl_package_905M2(void)
|
||||
{
|
||||
return is_meson_gxl_cpu() && package_id_is(0xe0);
|
||||
}
|
||||
|
||||
static inline bool is_meson_gxm_cpu(void)
|
||||
{
|
||||
return get_cpu_type() == MESON_CPU_MAJOR_ID_GXM;
|
||||
}
|
||||
|
||||
static inline bool is_meson_txl_cpu(void)
|
||||
{
|
||||
return get_cpu_type() == MESON_CPU_MAJOR_ID_TXL;
|
||||
}
|
||||
|
||||
static inline bool cpu_after_eq(unsigned int id)
|
||||
{
|
||||
return get_cpu_type() >= id;
|
||||
}
|
||||
|
||||
#endif
|
||||
90
include/linux/amlogic/scpi_protocol.h
Normal file
90
include/linux/amlogic/scpi_protocol.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* include/linux/amlogic/scpi_protocol.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SCPI_PROTOCOL_H_
|
||||
#define _SCPI_PROTOCOL_H_
|
||||
#include <linux/types.h>
|
||||
|
||||
enum scpi_client_id {
|
||||
SCPI_CL_NONE,
|
||||
SCPI_CL_CLOCKS,
|
||||
SCPI_CL_DVFS,
|
||||
SCPI_CL_POWER,
|
||||
SCPI_CL_THERMAL,
|
||||
SCPI_CL_REMOTE,
|
||||
SCPI_CL_LED_TIMER,
|
||||
SCPI_MAX,
|
||||
};
|
||||
|
||||
enum scpi_std_cmd {
|
||||
SCPI_CMD_INVALID = 0x00,
|
||||
SCPI_CMD_SCPI_READY = 0x01,
|
||||
SCPI_CMD_SCPI_CAPABILITIES = 0x02,
|
||||
SCPI_CMD_EVENT = 0x03,
|
||||
SCPI_CMD_SET_CSS_PWR_STATE = 0x04,
|
||||
SCPI_CMD_GET_CSS_PWR_STATE = 0x05,
|
||||
SCPI_CMD_CFG_PWR_STATE_STAT = 0x06,
|
||||
SCPI_CMD_GET_PWR_STATE_STAT = 0x07,
|
||||
SCPI_CMD_SYS_PWR_STATE = 0x08,
|
||||
SCPI_CMD_L2_READY = 0x09,
|
||||
SCPI_CMD_SET_AP_TIMER = 0x0a,
|
||||
SCPI_CMD_CANCEL_AP_TIME = 0x0b,
|
||||
SCPI_CMD_DVFS_CAPABILITIES = 0x0c,
|
||||
SCPI_CMD_GET_DVFS_INFO = 0x0d,
|
||||
SCPI_CMD_SET_DVFS = 0x0e,
|
||||
SCPI_CMD_GET_DVFS = 0x0f,
|
||||
SCPI_CMD_GET_DVFS_STAT = 0x10,
|
||||
SCPI_CMD_SET_RTC = 0x11,
|
||||
SCPI_CMD_GET_RTC = 0x12,
|
||||
SCPI_CMD_CLOCK_CAPABILITIES = 0x13,
|
||||
SCPI_CMD_SET_CLOCK_INDEX = 0x14,
|
||||
SCPI_CMD_SET_CLOCK_VALUE = 0x15,
|
||||
SCPI_CMD_GET_CLOCK_VALUE = 0x16,
|
||||
SCPI_CMD_PSU_CAPABILITIES = 0x17,
|
||||
SCPI_CMD_SET_PSU = 0x18,
|
||||
SCPI_CMD_GET_PSU = 0x19,
|
||||
SCPI_CMD_SENSOR_CAPABILITIES = 0x1a,
|
||||
SCPI_CMD_SENSOR_INFO = 0x1b,
|
||||
SCPI_CMD_SENSOR_VALUE = 0x1c,
|
||||
SCPI_CMD_SENSOR_CFG_PERIODIC = 0x1d,
|
||||
SCPI_CMD_SENSOR_CFG_BOUNDS = 0x1e,
|
||||
SCPI_CMD_SENSOR_ASYNC_VALUE = 0x1f,
|
||||
SCPI_CMD_SET_USR_DATA = 0x20,
|
||||
SCPI_CMD_COUNT
|
||||
};
|
||||
|
||||
struct scpi_opp_entry {
|
||||
u32 freq_hz;
|
||||
u32 volt_mv;
|
||||
} __packed;
|
||||
|
||||
struct scpi_dvfs_info {
|
||||
unsigned int count;
|
||||
unsigned int latency; /* in usecs */
|
||||
struct scpi_opp_entry *opp;
|
||||
} __packed;
|
||||
|
||||
|
||||
unsigned long scpi_clk_get_val(u16 clk_id);
|
||||
int scpi_clk_set_val(u16 clk_id, unsigned long rate);
|
||||
int scpi_dvfs_get_idx(u8 domain);
|
||||
int scpi_dvfs_set_idx(u8 domain, u8 idx);
|
||||
struct scpi_dvfs_info *scpi_dvfs_get_opps(u8 domain);
|
||||
int scpi_get_sensor(char *name);
|
||||
int scpi_get_sensor_value(u16 sensor, u32 *val);
|
||||
int scpi_send_usr_data(u32 client_id, u32 *val, u32 size);
|
||||
#endif /*_SCPI_PROTOCOL_H_*/
|
||||
26
include/linux/amlogic/secmon.h
Normal file
26
include/linux/amlogic/secmon.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* include/linux/amlogic/secmon.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SEC_MON_H__
|
||||
#define __SEC_MON_H__
|
||||
|
||||
void __iomem *get_secmon_sharemem_input_base(void);
|
||||
void __iomem *get_secmon_sharemem_output_base(void);
|
||||
void sharemem_mutex_lock(void);
|
||||
void sharemem_mutex_unlock(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user