20 Commits

Author SHA1 Message Date
LevitatingBusinessMan (Rein Fernhout)
b9cf70c75d use register satp instead of sptbr
the register was renamed
2025-02-03 09:40:30 +08:00
清欢
f6b3a51dab remove regulator_enable from dwc3 suspend & resume for rvbook 2024-07-21 00:17:45 +08:00
hlb194802
2a1c09c089 usb driver: dwc3-thead: fix wrong regulator disable in dwc3_thead_pm_suspend regulater mismatch in dwc3_thead_pm_suspend with hub1v2 vs hubswitch
Change-Id: I33243a3cae63751f6b2c985a85d50916e85afdcd
2024-07-21 00:17:45 +08:00
huaming.jiang
745c35085c driver:dw_i2c:detect rx fifo over and do retry
1. dw_i2c for hw not enable IC_EMPTYFIFO_HOLD_MASTER_EN,RX FIFO may
over if SW not read RX FIFO day timely.So enabel RX OVER INT,when
receive RX OVER ,i2c_dw_xfer return -EAGAIN,to trigger retry.
2. for large i2c read, set DW_IC_RX_TL to rx_fifo_depth / 2, to make more
efficient irq process.
3.skip isr once rx over by disable INT
4. merge fix from upstream
commit 301c8f5c32c8fb79c67539bc23972dc3ef48024c
Author: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Date:   Tue Sep 27 16:56:44 2022 +0300

    i2c: designware: Fix handling of real but unexpected device interrupts

    Commit c7b79a752871 ("mfd: intel-lpss: Add Intel Alder Lake PCH-S PCI
    IDs") caused a regression on certain Gigabyte motherboards for Intel
    Alder Lake-S where system crashes to NULL pointer dereference in
    i2c_dw_xfer_msg() when system resumes from S3 sleep state ("deep").

    I was able to debug the issue on Gigabyte Z690 AORUS ELITE and made
    following notes:

    - Issue happens when resuming from S3 but not when resuming from
      "s2idle"
    - PCI device 00:15.0 == i2c_designware.0 is already in D0 state when
      system enters into pci_pm_resume_noirq() while all other i2c_designware
      PCI devices are in D3. Devices were runtime suspended and in D3 prior
      entering into suspend
    - Interrupt comes after pci_pm_resume_noirq() when device interrupts are
      re-enabled
    - According to register dump the interrupt really comes from the
      i2c_designware.0. Controller is enabled, I2C target address register
      points to a one detectable I2C device address 0x60 and the
      DW_IC_RAW_INTR_STAT register START_DET, STOP_DET, ACTIVITY and
      TX_EMPTY bits are set indicating completed I2C transaction.

    My guess is that the firmware uses this controller to communicate with
    an on-board I2C device during resume but does not disable the controller
    before giving control to an operating system.

    I was told the UEFI update fixes this but never the less it revealed the
    driver is not ready to handle TX_EMPTY (or RX_FULL) interrupt when device
    is supposed to be idle and state variables are not set (especially the
    dev->msgs pointer which may point to NULL or stale old data).

    Introduce a new software status flag STATUS_ACTIVE indicating when the
    controller is active in driver point of view. Now treat all interrupts
    that occur when is not set as unexpected and mask all interrupts from
    the controller.

Change-Id: If81c92a03b9be8699742184b46c03df34f922a28
2024-07-21 00:17:45 +08:00
Han Gao
39a7c4f518 config: enable CONFIG_SCHED_MC
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
2024-07-21 00:17:45 +08:00
o_bianhq
99a0ff503d enable CONFIG_SCHED_MC
Change-Id: I46b9d8ba6e327106f130f8ea40fa1af1a55b9ca5
2024-07-21 00:17:45 +08:00
Song Shuai
483521ff86 riscv: Kconfig: enable SCHED_MC kconfig
RISC-V now builds the sched domain based on the simple possible map.

Enable SCHED_MC to make the building based on cpu_coregroup_mask()
which also takes care of the NUMA and cores with LLC.

Signed-off-by: Song Shuai <suagrfillet@gmail.com>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Link: https://lore.kernel.org/r/20230310110336.970985-1-suagrfillet@gmail.com
Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
Signed-off-by: Raul Xiong <huanyi.xj@alibaba-inc.com>
Change-Id: I9729fcd884478e369957d9b96421598cdafe3a51
(cherry picked from commit dc55601c64f5635c75cb3cdf9cd40cb43593e966)
2024-07-21 00:17:45 +08:00
yjd01941629
9ffddd4172 For AIC8800 (WIFI/BT chip): The AIC8800 driver must be unloaded before entering STR (Suspend to RAM); otherwise, upon waking from STR, initialization will fail.
1.broken-cd: The default non-removable attribute fails to recognize the AIC8800, thus it is set to rely on a software card detection signal instead of hardware, always treating the card slot as if a card is present.
2.keep-power-in-suspend: The SDIO of TH1520 does not support keeping power when entering STR, and the driver of AIC8800 does not support SDIO with this function. Therefore, this node is added here to meet the driver requirements of AIC8800.
3.support_power_ctrl:The newly added device node is used to control the WL-REG-ON signal (which controls the power of AIC8800) after waking up from STR.

Change-Id: Ia33309da9f3e6bdf291f408d26909f11afd24842
2024-07-21 00:17:45 +08:00
Han Gao
a8a3aef9b9 Revert "temp fix: disable poweron pin for aic8800 to make it work"
This reverts commit 6f712a1d7f.
2024-07-21 00:17:45 +08:00
hlb194802
3bff12eab2 virtio_vdmabuf: dma skip cpu sync if buf flag has VIRTIO_VDAMBUF_NONCACHED optimize cpu usage for nonecached dma buf used in g2d gpu vpu etc.
Change-Id: I191ebe6ad748dc9cb8f1946d1e51f6d606bde182
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
2024-07-21 00:17:45 +08:00
Han Gao
8e7282e217 vidmem:kernel: fixup unsafe release of allocater and dmabuf
This commit fixup unsafe release of allocater and dmabuf.
have merged
vidmem:kernel: update dmabuf release not free by allocate release.

Prev commit add release of dmabuf may caused mem node list
removed racing.Here have moved the exported node to global
list.

Signed-off-by: xianbing Zhu <xianbing.zhu@linux.alibaba.com>
Change-Id: I8c2a83b60f7d6ff26771550cc691db6b27b73609
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
2024-07-21 00:17:45 +08:00
Han Gao
d2247b2403 vidmem: implement dma_buf_ops release to free buffers
This commit implement dma_buf_ops release to free buffer
in function _dmabuf_release(struct dma_buf *dmabuf).

Default use  pr_debug for dynamic debug in macro DEBUG_PRINT.

Signed-off-by: xianbing Zhu <xianbing.zhu@linux.alibaba.com>
Change-Id: Id0a5841ccf8459c469034866dd2878e8698a57a4
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
2024-07-21 00:17:45 +08:00
Han Gao
3ef68d010b sync: SDK 1.5.4 video_memory
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
2024-07-21 00:17:45 +08:00
Han Gao
930b7d92fd vc8000e-kernel: fixup vcmdbuf release leak issue
This issue is reported in TLV-299.
This commit fixed allocate_cmdbuf may infinite loop
and leak of release the cmdbuf only reserved but not
link_and_run.
If cmdbuf not run done when release,do not firstly abort,
instead wait done event reduce abort failed.

Add cmdbuf id and line info for error log.
Fixed busy count record idle twice in read module all
regs issue.

Signed-off-by: xianbing Zhu <xianbing.zhu@linux.alibaba.com>
Change-Id: Ia006f8123e38022400959bed838ef76f7aef14a0
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
2024-07-21 00:17:45 +08:00
Han Gao
9ee78c8b51 vc8000d-kernel: fixup vcmdbuf release leak issue
This issue is reported in TLV-299.
This commit fixed allocate_cmdbuf may infinite loop
and leak of release the cmdbuf only reserved but not
link_and_run.
If cmdbuf not run done when release,do not firstly abort,
instead wait done event reduce abort failed.

Add cmdbuf id and line info for error log.
Fixed busy count record idle twice in read module all
regs issue.

Signed-off-by: xianbing Zhu <xianbing.zhu@linux.alibaba.com>
Change-Id: Ieb0b751d18a1ed65fe198e3d75a6953dabf15ef8
Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
2024-07-21 00:17:45 +08:00
Haaland Chen
719387f851 arch: riscv: thead: milkv-meles: increase HDMI pin drive strength
Fixed the issue where HDMI maximum resolution is 1024x768.
With this commit added, the maximum HDMI resolution is 4K.

Signed-off-by: Haaland Chen <haaland@milkv.io>
2024-07-06 19:24:41 +08:00
Carlos Giraldo
93090f65c3 config: enable required flags for k3s
check-config.sh script of k3s kubernetes light distribution flags the following configs as missing:

CONFIG_NETFILTER_XT_MATCH_COMMENT
CONFIG_NETFILTER_XT_MATCH_MULTIPORT
CONFIG_IP_SET
CONFIG_INET_XFRM_MODE_TRANSPORT
2024-07-06 19:16:38 +08:00
Haaland Chen
32bd505b1d riscv: dts: thead: add DDR-16GB meles
Signed-off-by: Haaland Chen <haaland@milkv.io>
2024-07-06 19:16:10 +08:00
0x754C
e3d0728cb3 Update th1520-lpi4a-plastic.dts
update screen timing
2024-07-06 19:15:14 +08:00
Lu
9cc3fa38f8 lpi4a: add pocket4a & plastic4a initial support 2024-07-06 19:15:14 +08:00
30 changed files with 1271 additions and 394 deletions

View File

@@ -326,6 +326,14 @@ config SMP
If you don't know what to do here, say N.
config SCHED_MC
bool "Multi-core scheduler support"
depends on SMP
help
Multi-core scheduler support improves the CPU scheduler's decision
making when dealing with multi-core CPU chips at a cost of slightly
increased overhead in some places. If unsure say N here.
config NR_CPUS
int "Maximum number of CPUs (2-32)"
range 2 32

View File

@@ -56,10 +56,12 @@ dtb-$(CONFIG_SOC_THEAD_FIRE) += fire-emu-soc-base-sec.dtb
dtb-$(CONFIG_SOC_THEAD) += th1520-beagle.dtb
dtb-$(CONFIG_SOC_THEAD) += th1520-lpi4a-16gb.dtb
dtb-$(CONFIG_SOC_THEAD) += th1520-lpi4a-laptop.dtb
dtb-$(CONFIG_SOC_THEAD) += th1520-lpi4a-pocket.dtb
dtb-$(CONFIG_SOC_THEAD) += th1520-lpi4a-console.dtb th1520-lpi4a-console-16g.dtb
dtb-$(CONFIG_SOC_THEAD) += th1520-lpi4a-plastic.dtb th1520-lpi4a-plastic-16g.dtb
dtb-$(CONFIG_SOC_THEAD) += th1520-lpi4a-cluster.dtb th1520-lpi4a-cluster-16gb.dtb
dtb-$(CONFIG_SOC_THEAD) += th1520-lpi4a-z14inch-m0.dtb th1520-lpi4a-z14inch-m0-16g.dtb
dtb-$(CONFIG_SOC_THEAD) += th1520-milkv-meles.dtb th1520-milkv-meles-4g.dtb th1520-milkv-meles-dsi0.dtb
dtb-$(CONFIG_SOC_THEAD) += th1520-milkv-meles.dtb th1520-milkv-meles-4g.dtb th1520-milkv-meles-16g.dtb th1520-milkv-meles-dsi0.dtb
# compat old name
dtb-$(CONFIG_SOC_THEAD) += light-lpi4a.dtb light-lpi4a-16gb.dtb

View File

@@ -32,7 +32,7 @@
};
&i2c3 {
touch@14 {
goodix_tp: touch@14 {
#gpio-cells = <2>;
compatible = "goodix,gt9271";
reg = <0x14>;

View File

@@ -11,7 +11,7 @@
};
&i2c3 {
touch@14 {
goodix_tp: touch@14 {
touchscreen-size-x = <800>;
touchscreen-size-y = <1200>;
status = "okay";

View File

@@ -76,9 +76,17 @@
vin-supply = <&reg_sys_vcc_5v>;
gpio = <&pcal6408ahk_c 1 1>;
enable-active-high;
regulator-boot-on;
regulator-always-on;
};
sata_pwr_switch: sata-pwr-switch {
status = "okay";
compatible = "reg-userspace-consumer";
regulator-name = "sata-pwr-consumer";
vcc-supply = <&reg_sata_vcc_5v>;
};
audio_amp: regulator-audio-amp-en {
status = "okay";
compatible = "regulator-fixed";
@@ -137,14 +145,12 @@
};
&wcn_wifi {
// WIFI,poweren_gpio = <&pcal6408ahk_c 4 0>;
/delete-property/ WIFI,poweren_gpio;
WIFI,poweren_gpio = <&pcal6408ahk_c 4 0>;
};
&wcn_bt {
// BT,power_gpio = <&pcal6408ahk_c 5 0>;
/delete-property/ BT,power_gpio;
BT,power_gpio = <&pcal6408ahk_c 5 0>;
};
&usb_1 {

View File

@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2022 Alibaba Group Holding Limited.
*/
#include "th1520-lpi4a-plastic.dts"
/ {
memory@0 {
device_type = "memory";
reg = <0x0 0x200000 0x3 0xffe00000>;
};
};
&cmamem {
alloc-ranges = <0x3 0xe4000000 0 0x14000000>; // [0x3E400_0000 ~ 0x3F800_0000]
};

View File

@@ -0,0 +1,78 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2024 Sipeed.
*/
#include <dt-bindings/interrupt-controller/irq.h>
#include "th1520-lpi4a-laptop.dts"
/ {
model = "T-HEAD Light Lichee Pi 4A configuration for Plastic laptop";
};
&dsi0_panel0 {
compatible = "cmn,5171_1920x1200_40Hz";
};
&i2c2 {
touchpad: touchpad@2c {
compatible = "hid-over-i2c";
reg = <0x2c>;
hid-descr-addr = <0x0020>;
interrupt-parent = <&gpio1_porta>;
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
};
};
&cw2015 {
cellwise,battery-profile = /bits/ 8 <
0x17 0x67 0x72 0x68 0x66 0x63 0x62 0x5A
0x64 0x61 0x4D 0x57 0x5A 0x51 0x43 0x38
0x31 0x2A 0x24 0x22 0x29 0x31 0x3E 0x4C
0x29 0x4D 0x0B 0x85 0x1C 0x38 0x47 0x57
0x5D 0x5E 0x5F 0x60 0x3F 0x1A 0x6F 0x41
0x0A 0x43 0x12 0x38 0x7B 0x95 0x9A 0x18
0x4B 0x6F 0x9E 0xD5 0x80 0x57 0x87 0xCB
0x2F 0x00 0x64 0xA5 0xB5 0x13 0x54 0xB9
>;
};
&lt8911 {
// CMN5171
lontium,pclk = <160000000>; // 60Hz
lontium,hact = <1920>;
lontium,vact = <1200>;
lontium,hbp = <105>;
lontium,hfp = <58>;
lontium,vbp = <20>;
lontium,vfp = <10>;
lontium,hs = <37>;
lontium,vs = <6>;
lontium,mipi_lane = <2>;
lontium,lane_cnt = <2>;
lontium,color = <1>; //Color Depth 0:6bit 1:8bit
lontium,test = <0>;
};
&fan_config0 {
temperature = <40000>;
};
&fan_config1 {
temperature = <60000>;
};
&fan_config2 {
temperature = <80000>;
};
&fan {
pwms = <&pwm 1 100000 0>;
cooling-levels = <0x10 0x30 0x50 0xFF>;
};
&lcd0_backlight {
//pwms = <&pwm 0 50000>;
pwms = <&pwm 0 1000000>;
default-brightness-level = <40>;
};

View File

@@ -0,0 +1,219 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2023 Sipeed.
*/
#include "th1520-lpi4a-dsi0-hdmi.dts"
/ {
model = "LicheePocket4A 8G";
compatible = "thead,light", "sipeed,pocket4a";
charger: dc-charger {
compatible = "gpio-charger";
charger-type = "mains";
gpios = <&gpio1_porta 3 GPIO_ACTIVE_HIGH>;
};
};
&uart1 {
status = "okay";
};
&uart3 {
status = "okay";
};
&lcd0_backlight {
pwms = <&pwm 0 10000>; // 100Khz
brightness-levels = <0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100>;
default-brightness-level = <30>;
};
&fan {
pwms = <&pwm 1 10000000 0>;
//cooling-levels = <0 64 192 255>;
cooling-levels = <192 192 192 255>;
};
&i2c0 {
/delete-node/ gpio@18;
cw2015: cw2015@62 {
compatible = "cellwise,cw2015";
status = "disabled";
reg = <0x62>;
cellwise,monitor-interval-ms = <5000>;
power-supplies = <&charger>;
cellwise,battery-profile = /bits/ 8 <
0x17 0x67 0x80 0x73 0x6E 0x6C 0x6B 0x63
0x77 0x51 0x5C 0x58 0x50 0x4C 0x48 0x36
0x15 0x0C 0x0C 0x19 0x5B 0x7D 0x6F 0x69
0x69 0x5B 0x0C 0x29 0x20 0x40 0x52 0x59
0x57 0x56 0x54 0x4F 0x3B 0x1F 0x7F 0x17
0x06 0x1A 0x30 0x5A 0x85 0x93 0x96 0x2D
0x48 0x77 0x9C 0xB3 0x80 0x52 0x94 0xCB
0x2F 0x00 0x64 0xA5 0xB5 0x11 0xF0 0x11
>;
};
};
&i2c3 {
/delete-node/ gpio@18;
};
&goodix_tp {
#gpio-cells = <2>;
compatible = "goodix,gt9271";
reg = <0x14>;
interrupt-parent = <&ao_gpio_porta>;
interrupts = <3 0>;
irq-gpios = <&ao_gpio_porta 3 0>;
reset-gpios = <&pcal6408ahk_c 0 0>;
touchscreen-size-x = <800>;
touchscreen-size-y = <1280>;
status = "okay";
};
&reg_tp_pwr_en {
/delete-property/ gpio;
};
&reg_usb_hub_vdd1v2 {
/delete-property/ gpio;
};
&vvcam_sensor1 {
sensor_pdn = <&gpio1_porta 30 0>;
sensor_rst = <&pcal6408ahk_c 2 0>;
i2c_bus = /bits/ 8 <0>;
};
&key_volup {
gpios = <&gpio2_porta 16 0x1>;
};
&reg_usb_hub_vcc5v {
/delete-property/ gpio;
};
&soc_vdd33_lcd0_en_reg {
/delete-property/ gpio;
};
&soc_vdd18_lcd0_en_reg {
/delete-property/ gpio;
};
&soc_avdd28_rgb_reg {
/delete-property/ gpio;
};
&soc_dovdd18_rgb_reg {
/delete-property/ gpio;
};
&soc_dvdd12_rgb_reg {
/delete-property/ gpio;
};
&soc_avdd25_ir_reg {
/delete-property/ gpio;
};
&soc_dovdd18_ir_reg {
/delete-property/ gpio;
};
&soc_dvdd12_ir_reg {
/delete-property/ gpio;
};
&soc_cam2_avdd25_ir_reg {
/delete-property/ gpio;
};
&soc_cam2_dovdd18_ir_reg {
/delete-property/ gpio;
};
&soc_cam2_dvdd12_ir_reg {
/delete-property/ gpio;
};
&dsi0_panel0 {
compatible = "chongzhou,cz101b4001", "jadard,jd9365da-h3";
backlight = <&lcd0_backlight>;
reset-gpio = <&pcal6408ahk_c 3 0>; /* active low */
/delete-property/ hsvcc-supply;
/delete-property/ vspn3v3-supply;
};
&usb_1 {
/delete-property/ hubswitch-gpio;
/delete-property/ hub1v2-supply;
/delete-property/ hub5v-supply;
};
&cpus {
c910_0: cpu@0 {
operating-points = <
/* kHz uV */
300000 500000
800000 700000
1500000 800000
>;
light,dvddm-operating-points = <
/* kHz uV */
300000 800000
800000 800000
1500000 800000
>;
};
c910_1: cpu@1 {
operating-points = <
/* kHz uV */
300000 500000
800000 700000
1500000 800000
>;
light,dvddm-operating-points = <
/* kHz uV */
300000 800000
800000 800000
1500000 800000
>;
};
c910_2: cpu@2 {
operating-points = <
/* kHz uV */
300000 500000
800000 700000
1500000 800000
>;
light,dvddm-operating-points = <
/* kHz uV */
300000 800000
800000 800000
1500000 800000
>;
};
c910_3: cpu@3 {
operating-points = <
/* kHz uV */
300000 500000
800000 700000
1500000 800000
>;
light,dvddm-operating-points = <
/* kHz uV */
300000 800000
800000 800000
1500000 800000
>;
};
};

View File

@@ -273,7 +273,8 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_wifi_wake>;
wifi_chip_type = "rtl8723ds";
// WIFI,poweren_gpio = <&pcal6408ahk_c 4 0>;
WIFI,poweren_gpio = <&pcal6408ahk_c 4 0>;
support_power_ctrl;
status = "okay";
};
@@ -281,7 +282,7 @@
compatible = "bluetooth-platdata";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_bt_wake>;
// BT,power_gpio = <&pcal6408ahk_c 5 0>;
BT,power_gpio = <&pcal6408ahk_c 5 0>;
status = "okay";
};
@@ -295,7 +296,7 @@
debounce-interval = <1>;
gpios = <&gpio1_porta 19 0x1>;
};
key-volumeup {
key_volup: key-volumeup {
label = "Volume Up Key";
linux,code = <KEY_VOLUMEUP>;
debounce-interval = <1>;
@@ -992,12 +993,13 @@
pull_up;
no-sd;
no-mmc;
non-removable;
broken-cd;
io_fixed_1v8;
post-power-on-delay-ms = <50>;
wprtn_ignore;
cap-sd-highspeed;
wakeup-source;
keep-power-in-suspend;
status = "okay";
};
@@ -1174,7 +1176,6 @@
>;
};
pinctrl_uart3_tx_is_gpio: uart3txisgpiogrp {
thead,pins = <
FM_UART3_TXD 0x3 0x202
@@ -1184,6 +1185,7 @@
pinctrl_wifi_wake: wifi_grp {
thead,pins = <
FM_GPIO0_27 0x0 0x202
@@ -1525,6 +1527,13 @@
channel0 {
channel_id = <0>;
status = "okay";
sensor0 {
subdev_name = "vivcam";
idx = <0>;
csi_idx = <0>;
mode_idx = <0>;
path_type = "SENSOR_VGA_RAW12_LINER";
};
sensor1 {
subdev_name = "vivcam";
idx = <3>;
@@ -1550,6 +1559,13 @@
};
};
channel1 {
sensor0 {
subdev_name = "vivcam";
idx = <0>;
csi_idx = <0>;
mode_idx = <0>;
path_type = "SENSOR_VGA_RAW12_LINER";
};
sensor1 {
subdev_name = "vivcam";
idx = <3>;
@@ -1570,6 +1586,13 @@
};
};
channel2 {
sensor0 {
subdev_name = "vivcam";
idx = <0>;
csi_idx = <0>;
mode_idx = <0>;
path_type = "SENSOR_VGA_RAW12_LINER";
};
sensor1 {
subdev_name = "vivcam";
idx = <3>;
@@ -1595,6 +1618,14 @@
vi_mem_pool_region = <0>; // vi_mem: framebuffer, region[0]
status = "okay";
channel0 {
sensor0 {
subdev_name = "vivcam";
idx = <0>;
csi_idx = <0>;
mode_idx = <0>;
path_type = "SENSOR_VGA_RAW12_LINER";
};
sensor1 {
subdev_name = "vivcam";
idx = <3>;

View File

@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2022 Alibaba Group Holding Limited.
*/
#include "th1520-milkv-meles.dts"
/ {
memory@0 {
device_type = "memory";
reg = <0x0 0x200000 0x3 0xffe00000>;
};
};
&cmamem {
alloc-ranges = <0x3 0xe4000000 0 0x14000000>; // [0x3E400_0000 ~ 0x3F800_0000]
};

View File

@@ -848,12 +848,11 @@
pinctrl_hdmi: hdmigrp {
thead,pins = <
FM_HDMI_SCL 0x0 0x202
FM_HDMI_SDA 0x0 0x202
FM_HDMI_CEC 0x0 0x202
FM_HDMI_SCL 0x0 0x208
FM_HDMI_SDA 0x0 0x208
FM_HDMI_CEC 0x0 0x208
>;
};
pinctrl_gmac0: gmac0grp {
thead,pins = <
FM_GMAC0_TX_CLK 0x0 0x20f /* GMAC0_TX_CLK */

View File

@@ -10,6 +10,7 @@ CONFIG_NAMESPACES=y
CONFIG_USER_NS=y
CONFIG_CHECKPOINT_RESTORE=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_SCHED_MC=y
CONFIG_EXPERT=y
# CONFIG_BUG is not set
CONFIG_BPF_SYSCALL=y

View File

@@ -29,6 +29,7 @@ CONFIG_NAMESPACES=y
CONFIG_USER_NS=y
CONFIG_CHECKPOINT_RESTORE=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_SCHED_MC=y
CONFIG_EXPERT=y
# CONFIG_BUG is not set
CONFIG_KALLSYMS_ALL=y
@@ -70,6 +71,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM_USER=y
CONFIG_INET=y
CONFIG_IP_SET=y
CONFIG_IP_MULTICAST=y
CONFIG_IP_ADVANCED_ROUTER=y
CONFIG_IP_PNP=y
@@ -78,6 +80,7 @@ CONFIG_IP_PNP_BOOTP=y
CONFIG_IP_PNP_RARP=y
CONFIG_NET_IPVTI=y
CONFIG_INET_ESP=y
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_TCP_CONG_ADVANCED=y
CONFIG_TCP_CONG_BBR=m
CONFIG_NETFILTER=y
@@ -92,9 +95,11 @@ CONFIG_NETFILTER_XT_NAT=y
CONFIG_NETFILTER_XT_TARGET_REDIRECT=y
CONFIG_NETFILTER_XT_TARGET_MASQUERADE=y
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=y
CONFIG_NETFILTER_XT_MATCH_COMMENT=y
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y
CONFIG_NETFILTER_XT_MATCH_IPVS=y
CONFIG_NETFILTER_XT_MATCH_MARK=y
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
CONFIG_IP_VS=y
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y
@@ -239,6 +244,10 @@ CONFIG_LIGHT_PMIC_WATCHDOG=y
CONFIG_ABX500_CORE=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_VIRTUAL_CONSUMER=y
CONFIG_REGULATOR_USERSPACE_CONSUMER=y
CONFIG_REGULATOR_GPIO=y
CONFIG_REGULATOR_PWM=y
CONFIG_MEDIA_SUPPORT=y
# CONFIG_MEDIA_ANALOG_TV_SUPPORT is not set
# CONFIG_MEDIA_DIGITAL_TV_SUPPORT is not set
@@ -293,7 +302,7 @@ CONFIG_DRM_PANEL_HX8394=y
CONFIG_DRM_PANEL_JADARD_JD9365DA_H3=y
CONFIG_DRM_PANEL_MINGJUN_070BI30IA2=y
CONFIG_DRM_PANEL_HX8279=y
CONFIG_DRM_LONTIUM_LT8911EXB=m
CONFIG_DRM_LONTIUM_LT8911EXB=y
CONFIG_DRM_ETNAVIV=m
CONFIG_DRM_VERISILICON=y
CONFIG_DRM_POWERVR_ROGUE=m
@@ -314,8 +323,10 @@ CONFIG_SND_SOC_ES8156=y
CONFIG_SND_SOC_WM8960=y
CONFIG_SND_SIMPLE_CARD=y
CONFIG_SND_AUDIO_GRAPH_CARD=y
CONFIG_HIDRAW=m
CONFIG_UHID=y
CONFIG_HID_PID=y
CONFIG_HID_MULTITOUCH=m
CONFIG_USB_HIDDEV=y
CONFIG_I2C_HID=m
CONFIG_USB=y

View File

@@ -98,7 +98,7 @@ void switch_mm(struct mm_struct *prev, struct mm_struct *next,
"sfence.vma t0, t0\n\t"
::: "memory", "t0");
csr_write(sptbr, virt_to_pfn(next->pgd) | SATP_MODE | asid);
csr_write(satp, virt_to_pfn(next->pgd) | SATP_MODE | asid);
#endif
flush_icache_deferred(next);

View File

@@ -4570,6 +4570,37 @@ static const struct panel_desc_dsi z14inch_2160x1440_40Hz = {
};
/* TODO: move timing into device tree */
static const struct drm_display_mode cmn_5171_1920x1200_40Hz_mode = {
.clock = 127750,
.hdisplay = 1920,
.hsync_start = 1920 + 46, /* hact + hfp */
.hsync_end = 1920 + 46 + 30, /* hact + hfp + hs */
.htotal = 1920 + 46 + 30 + 84, /* hact + hfp + hs + hbp */
.vdisplay = 1200,
.vsync_start = 1200 + 10, /* vact + vfp */
.vsync_end = 1200 + 10 + 6, /* vact + vfp + vs */
.vtotal = 1200 + 10 + 6 + 20, /* vact + vfp + vs + vbp */
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
};
static const struct panel_desc_dsi cmn_5171_1920x1200_40Hz = {
.desc = {
.modes = &cmn_5171_1920x1200_40Hz_mode,
.num_modes = 1,
.bpc = 8,
.size = {
.width = 62,
.height = 110,
},
.connector_type = DRM_MODE_CONNECTOR_DSI,
},
.flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_VIDEO_BURST,
.format = MIPI_DSI_FMT_RGB888,
.lanes = 4,
};
static const struct drm_display_mode lg_ld070wx3_sl01_mode = {
.clock = 71000,
.hdisplay = 800,
@@ -4771,6 +4802,9 @@ static const struct of_device_id dsi_of_match[] = {
}, {
.compatible = "custom,z14inch_2160x1440_40Hz",
.data = &z14inch_2160x1440_40Hz
}, {
.compatible = "cmn,5171_1920x1200_40Hz",
.data = &cmn_5171_1920x1200_40Hz
}, {
/* sentinel */
}

View File

@@ -126,8 +126,9 @@
* status codes
*/
#define STATUS_IDLE 0x0
#define STATUS_WRITE_IN_PROGRESS 0x1
#define STATUS_READ_IN_PROGRESS 0x2
#define STATUS_ACTIVE 0x1
#define STATUS_WRITE_IN_PROGRESS 0x2
#define STATUS_READ_IN_PROGRESS 0x4
/*
* operation modes
@@ -331,12 +332,14 @@ void i2c_dw_disable_int(struct dw_i2c_dev *dev);
static inline void __i2c_dw_enable(struct dw_i2c_dev *dev)
{
dev->status |= STATUS_ACTIVE;
regmap_write(dev->map, DW_IC_ENABLE, 1);
}
static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev)
{
regmap_write(dev->map, DW_IC_ENABLE, 0);
dev->status &= ~STATUS_ACTIVE;
}
void __i2c_dw_disable(struct dw_i2c_dev *dev);

View File

@@ -261,9 +261,9 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
if (dev->dw_i2c_enable_dma) {
i2c_dw_xfer_dma_init(dev);
regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK & (~DW_IC_INTR_TX_EMPTY));
regmap_write(dev->map, DW_IC_INTR_MASK, (DW_IC_INTR_MASTER_MASK & (~DW_IC_INTR_TX_EMPTY))|DW_IC_INTR_RX_OVER);
} else {
regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK);
regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK|DW_IC_INTR_RX_OVER);
}
}
@@ -433,7 +433,6 @@ i2c_dw_read(struct dw_i2c_dev *dev)
}
regmap_read(dev->map, DW_IC_RXFLR, &rx_valid);
for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
u32 flags = msgs[dev->msg_read_idx].flags;
@@ -546,12 +545,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
}
if (dev->status || dev->tx_status) {
dev_err(dev->dev, "transfer terminated early - interrupt latency too high? sta 0x%x\n", dev->status);
dev_err(dev->dev, "laststa 0x%x, laststatus 0x%x\n", dev->laststat, dev->laststatus);
dev_err(dev->dev, "dev->tx_status 0x%x\n", dev->tx_status);
dev_err(dev->dev, "dev->rx_outstanding %d\n", dev->rx_outstanding);
}
dev_err(dev->dev, "transfer terminated early - interrupt latency too high? sta 0x%x,tx_status 0x%x\n",dev->status,dev->tx_status);
dev_err(dev->dev, "laststa 0x%x, laststatus 0x%x,rx_outstanding %d\n", dev->laststat, dev->laststatus, dev->rx_outstanding);
if(dev->laststat&DW_IC_INTR_RX_OVER)
{
ret = -EAGAIN;
goto done;
}
}
ret = -EIO;
@@ -640,6 +641,19 @@ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev)
u32 stat, status;
stat = i2c_dw_read_clear_intrbits(dev);
if(!(dev->status & STATUS_ACTIVE)) {
/*
* Unexpected interrupt in driver point of view. State
* variables are either unset or stale so acknowledge and
* disable interrupts for suppressing further interrupts if
* interrupt really came from this HW (E.g. firmware has left
* the HW active).
*/
regmap_write(dev->map, DW_IC_INTR_MASK, 0);
return 0;
}
if (stat & DW_IC_INTR_TX_ABRT) {
dev->cmd_err |= DW_IC_ERR_TX_ABRT;
dev->status = STATUS_IDLE;
@@ -653,8 +667,13 @@ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev)
}
goto tx_aborted;
}
if (stat & DW_IC_INTR_RX_FULL)
if(stat & DW_IC_INTR_RX_OVER)
{
/* Anytime RX_OVER is set, Make sure to skip them.*/
regmap_write(dev->map, DW_IC_INTR_MASK, 0);
goto tx_aborted;
}
if ((stat & DW_IC_INTR_RX_FULL) || (dev->rx_outstanding >0))
i2c_dw_read(dev);
if (stat & DW_IC_INTR_TX_EMPTY) {
@@ -669,13 +688,14 @@ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev)
tx_aborted:
regmap_read(dev->map, DW_IC_STATUS, &status);
if ((stat & DW_IC_INTR_TX_ABRT) || dev->msg_err ||
if ((stat & (DW_IC_INTR_TX_ABRT|DW_IC_INTR_RX_OVER))|| dev->msg_err ||
((status & DW_IC_STATUS_TFE) &&
(!(status & DW_IC_STATUS_RFNE)) &&
(!(status & DW_IC_STATUS_MASTER_ACTIVITY)))) {
dev->laststat = stat;
dev->laststatus = status;
complete(&dev->cmd_complete);
dev->laststat = stat;
dev->laststatus = status;
} else if (unlikely(dev->flags & ACCESS_INTR_MASK)) {
/* Workaround to trigger pending interrupt */
regmap_read(dev->map, DW_IC_INTR_MASK, &stat);
@@ -690,7 +710,8 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
{
struct dw_i2c_dev *dev = dev_id;
u32 stat, enabled;
if (pm_runtime_suspended(dev->dev))
return IRQ_NONE;
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat);
dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat);

View File

@@ -267,6 +267,25 @@ error:
return -1;
}
static int i2x_dw_get_read_size(struct dw_i2c_dev *dev)
{
struct i2c_msg *msgs = dev->msgs;
u32 addr = msgs[dev->msg_write_idx].addr;
int i = 0;
int len = 0;
__dev_vdgb(dev->dev, "%s, %d, enter\n", __func__, __LINE__);
for (i = dev->msg_write_idx; i < dev->msgs_num; i++) {
if (msgs[i].addr != addr) {
dev_err(dev->dev, "%s: invalid target address\n", __func__);
dev->msg_err = -EINVAL;
break;
}
if(msgs[i].flags & I2C_M_RD)
len += msgs[i].len;
}
__dev_vdgb(dev->dev, "%s, %d, exit\n", __func__, __LINE__);
return len;
}
int i2c_dw_xfer_dma_init(struct dw_i2c_dev *dev)
{
struct i2c_dw_dma *dma = &dev->dma;
@@ -275,6 +294,9 @@ int i2c_dw_xfer_dma_init(struct dw_i2c_dev *dev)
// i2c dma set tx data level
regmap_write(dev->map, DW_IC_DMA_TDLR, dev->tx_fifo_depth / 2);
if(i2x_dw_get_read_size(dev)>(dev->rx_fifo_depth / 2))
regmap_write(dev->map, DW_IC_RX_TL, dev->rx_fifo_depth / 2);
// i2c dma tx enable
regmap_write(dev->map, DW_IC_DMA_CR, DW_IC_DMA_CR_TXEN);

View File

@@ -2348,7 +2348,7 @@ void decoder_devfreq_record_busy(struct decoder_devfreq *devfreq)
decoder_dev_clk_lock();
spin_lock_irqsave(&devfreq->lock, irqflags);
busy_count = devfreq->busy_count;
//pr_info("record_busy:busy_count = %d\n",busy_count);
PDEBUG("record_busy:busy_count = %d\n",busy_count);
if(devfreq->busy_count > 0)
{
devfreq->busy_count++;
@@ -2376,7 +2376,7 @@ void decoder_devfreq_record_idle(struct decoder_devfreq *devfreq)
if (!devfreq)
return;
spin_lock_irqsave(&devfreq->lock, irqflags);
//pr_info("record_idle:busy_count = %d\n",devfreq->busy_count);
PDEBUG("record_idle:busy_count = %d\n",devfreq->busy_count);
if(devfreq->busy_count > 1)
{
devfreq->busy_count--;
@@ -2581,7 +2581,7 @@ int decoder_devfreq_init(struct device *dev)
int ret = 0;
struct decoder_devfreq *devfreq = decoder_get_devfreq_priv_data();
memset(devfreq,sizeof(struct decoder_devfreq),0);
memset(devfreq,0,sizeof(struct decoder_devfreq));
spin_lock_init(&devfreq->lock);
init_waitqueue_head(&devfreq->target_freq_wait_queue);
mutex_init(&devfreq->clk_mutex);

View File

@@ -1425,7 +1425,7 @@ static enum MMUStatus MMUMemNodeMap(struct addr_desc *addr, struct file *filp) {
page_count = (addr->size - 1)/PAGE_SIZE + 1;
GetPhysicalAddress(addr->virtual_address, &address);
MMUDEBUG(" *****MMU map address*****%x\n", address);
MMUDEBUG(" *****MMU map address*****%llx phys_to_virt %lx\n", address,(unsigned long)phys_to_virt(address));
if(address >= REGION_IN_START &&
address + addr->size < REGION_IN_END)
e = MMU_REGION_IN;
@@ -1505,7 +1505,7 @@ static enum MMUStatus MMUMemNodeMap(struct addr_desc *addr, struct file *filp) {
MMUDEBUG(" MMU_MTLB_SHIFT %d MMU_STLB_4K_SHIFT %d\n", MMU_MTLB_SHIFT, MMU_STLB_4K_SHIFT);
MMUDEBUG(" MMUMemNodeMap map total %d pages in region %d\nMTLB/STLB starts %d/%d, MTLB/STLB ends %d/%d\n",
page_count, (u32)e, p->mtlb_start, p->stlb_start, p->mtlb_end, p->stlb_end);
MMUDEBUG(" MMUMemNodeMap map %p -> 0x%08x\n", addr->virtual_address, addr->bus_address);
MMUDEBUG(" MMUMemNodeMap map %px -> 0x%08x\n", addr->virtual_address, addr->bus_address);
ReleaseMutex(g_mmu->page_table_mutex);

View File

@@ -580,6 +580,7 @@ struct process_manager_obj
u64 total_exe_time;
spinlock_t spinlock;
u32 pm_count;
wait_queue_head_t wait_queue;
} ;
@@ -602,7 +603,7 @@ struct cmdbuf_obj
u16 cmdbuf_id; //used to manage CMDBUF in driver.It is a handle to identify cmdbuf.also is an interrupt vector.position in pool,same as status position.
u8 cmdbuf_data_loaded; //0 means sw has not copied data into this CMDBUF; 1 means sw has copied data into this CMDBUF
u8 cmdbuf_data_linked; //0 :not linked, 1:linked.
u8 cmdbuf_run_done; //if 0,waiting for CMDBUF finish; if 1, op code in CMDBUF has finished one by one. HANTRO_VCMD_IOCH_WAIT_CMDBUF will check this variable.
volatile u8 cmdbuf_run_done; //if 0,waiting for CMDBUF finish; if 1, op code in CMDBUF has finished one by one. HANTRO_VCMD_IOCH_WAIT_CMDBUF will check this variable.
u8 cmdbuf_need_remove; // if 0, not need to remove CMDBUF; 1 CMDBUF can be removed if it is not the last CMDBUF;
u32 waited; // if 0, the cmd buf hasn't been waited, otherwise, has been waited.
u8 has_end_cmdbuf; //if 1, the last opcode is end opCode.
@@ -896,8 +897,47 @@ static void free_cmdbuf_mem(u16 cmdbuf_id )
spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
cmdbuf_used[cmdbuf_id]=0;
cmdbuf_used_residual +=1;
PDEBUG(" ## real free cmdbuf[%d]\n",cmdbuf_id);
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
wake_up_interruptible_all(&vcmd_cmdbuf_memory_wait);
wake_up_all(&vcmd_cmdbuf_memory_wait);
}
static void free_cmdbuf_not_linked_by_flip(struct file *filp)
{
unsigned long flags;
int i;
struct cmdbuf_obj* cmdbuf_obj;
bi_list_node* new_cmdbuf_node;
bool freed_flag = false;
spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
for(i = 0; i < TOTAL_DISCRETE_CMDBUF_NUM; i++)
{
if(cmdbuf_used[i] && global_cmdbuf_node[i] != NULL)
{
new_cmdbuf_node = global_cmdbuf_node[i];
if(new_cmdbuf_node == 0x55555555)
{
continue;
}
cmdbuf_obj = (struct cmdbuf_obj* )new_cmdbuf_node->data;
if(cmdbuf_obj->filp == filp && !cmdbuf_obj->cmdbuf_data_linked && !cmdbuf_obj->cmdbuf_run_done)
{
cmdbuf_used[i]=0;
cmdbuf_used_residual +=1;
global_cmdbuf_node[i] = NULL;
freed_flag = true;
PDEBUG(" ## Find left node not freed,real free cmdbuf[%d],remain %d\n",i,cmdbuf_used_residual);
}
}
if(cmdbuf_used_residual >= (TOTAL_DISCRETE_CMDBUF_NUM-2))
break;
}
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
if(freed_flag)
wake_up_all(&vcmd_cmdbuf_memory_wait);
}
static bi_list_node* create_cmdbuf_node(void)
@@ -907,8 +947,13 @@ static bi_list_node* create_cmdbuf_node(void)
struct noncache_mem new_cmdbuf_addr;
struct noncache_mem new_status_cmdbuf_addr;
if(wait_event_interruptible(vcmd_cmdbuf_memory_wait, allocate_cmdbuf(&new_cmdbuf_addr,&new_status_cmdbuf_addr)) )
if(!wait_event_interruptible_timeout(vcmd_cmdbuf_memory_wait, allocate_cmdbuf(&new_cmdbuf_addr,&new_status_cmdbuf_addr),
msecs_to_jiffies(500)) )
{
pr_err("wait allocate_cmdbuf timeout\n");
return NULL;
}
#ifdef DYNAMIC_MALLOC_VCMDNODE
cmdbuf_obj=create_cmdbuf_obj();
#else
@@ -1028,18 +1073,21 @@ static u64 calculate_executing_time_after_node_high_priority(bi_list_node* exe_c
}
return time_run_all;
}
#ifdef DEBUG_CMDBUF_ALLOC
int cmdbuf_node_unexpected[TOTAL_DISCRETE_CMDBUF_NUM];
#endif
/**********************************************************************************************************\
*cmdbuf pool management
\***********************************************************************************************************/
static int allocate_cmdbuf(struct noncache_mem* new_cmdbuf_addr,struct noncache_mem* new_status_cmdbuf_addr)
{
unsigned long flags;
u16 cmdbuf_used_pos_start = cmdbuf_used_pos;
spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
if(cmdbuf_used_residual==0)
{
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
pr_err("%s:no empty cmdbuf\n",__func__);
//no empty cmdbuf
return 0;
}
@@ -1060,6 +1108,7 @@ static int allocate_cmdbuf(struct noncache_mem* new_cmdbuf_addr,struct noncache
new_status_cmdbuf_addr->mmu_bus_address=vcmd_status_buf_mem_pool.mmu_bus_address + cmdbuf_used_pos*CMDBUF_MAX_SIZE;
new_status_cmdbuf_addr->size=CMDBUF_MAX_SIZE;
new_status_cmdbuf_addr->cmdbuf_id = cmdbuf_used_pos;
global_cmdbuf_node[cmdbuf_used_pos]=0x55555555; //temp set it,for another thread not hit cmdbuf_used[x] set but global_cmdbuf_node[x] is null
cmdbuf_used_pos++;
if(cmdbuf_used_pos>=TOTAL_DISCRETE_CMDBUF_NUM)
cmdbuf_used_pos=0;
@@ -1068,11 +1117,30 @@ static int allocate_cmdbuf(struct noncache_mem* new_cmdbuf_addr,struct noncache
}
else
{
#ifdef DEBUG_CMDBUF_ALLOC
if(cmdbuf_used[cmdbuf_used_pos]==0 && (global_cmdbuf_node[cmdbuf_used_pos]!=NULL ) && (cmdbuf_node_unexpected[cmdbuf_used_pos] == 0x55))
{
pr_warn("unexpected cmdbuf_used[%d] is 0,but global_cmdbuf_node[%d] != NULL\n",
cmdbuf_used_pos,cmdbuf_used_pos);
cmdbuf_node_unexpected[cmdbuf_used_pos] = 0x55;
}
else if(cmdbuf_used[cmdbuf_used_pos]!=0 && (global_cmdbuf_node[cmdbuf_used_pos] == NULL ) && (cmdbuf_node_unexpected[cmdbuf_used_pos] == 0x55))
{
pr_warn("unexpected cmdbuf_used[%d] != 0,but global_cmdbuf_node[%d] is NULL\n",
cmdbuf_used_pos,cmdbuf_used_pos);
cmdbuf_node_unexpected[cmdbuf_used_pos] = 0x55;
}
#endif
cmdbuf_used_pos++;
if(cmdbuf_used_pos>=TOTAL_DISCRETE_CMDBUF_NUM)
cmdbuf_used_pos=0;
if(cmdbuf_used_pos_start == cmdbuf_used_pos) //searched all,not find one,should return;
break;
}
}
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
pr_err("%s: no cmdbuf found,cmdbuf_used_residual %d\n",__func__,cmdbuf_used_residual);
return 0;
}
@@ -1113,7 +1181,9 @@ static int select_vcmd(bi_list_node* new_cmdbuf_node)
size_t exe_cmdbuf_addr=0;
struct cmdbuf_obj* cmdbuf_obj_temp=NULL;
u32 cmdbuf_id=0;
struct process_manager_obj* process_manager_temp;
cmdbuf_obj=(struct cmdbuf_obj*)new_cmdbuf_node->data;
//there is an empty vcmd to be used
while(1)
{
@@ -1446,7 +1516,7 @@ static long reserve_cmdbuf(struct file *filp,struct exchange_parameter* input_pa
{
return -1;
}
PDEBUG("reserve cmdbuf filp %p\n", (void *)filp);
PDEBUG("reserve cmdbuf filp %px\n", (void *)filp);
spin_lock_irqsave(&vcmd_process_manager_lock, flags);
process_manager_node = global_process_manager.head;
while(1)
@@ -1459,7 +1529,7 @@ static long reserve_cmdbuf(struct file *filp,struct exchange_parameter* input_pa
return -1;
}
process_manager_obj = (struct process_manager_obj*)process_manager_node->data;
PDEBUG("reserve loop: node %p, filp %p\n", (void *)process_manager_node,
PDEBUG("reserve loop: node %px, filp %px\n", (void *)process_manager_node,
(void *)process_manager_obj->filp);
if (filp == process_manager_obj->filp)
break;
@@ -1470,13 +1540,19 @@ static long reserve_cmdbuf(struct file *filp,struct exchange_parameter* input_pa
spin_lock_irqsave(&process_manager_obj->spinlock, flags);
process_manager_obj->total_exe_time += input_para->executing_time;
spin_unlock_irqrestore(&process_manager_obj->spinlock, flags);
if(wait_event_interruptible(process_manager_obj->wait_queue, wait_process_resource_rdy(process_manager_obj)))
return -1;
if(!wait_event_interruptible_timeout(process_manager_obj->wait_queue, wait_process_resource_rdy(process_manager_obj),
msecs_to_jiffies(500) ))
{
pr_err("wait_process_resource_rdy timeout! total_exe_time %lld\n",process_manager_obj->total_exe_time);
return -1;
}
new_cmdbuf_node=create_cmdbuf_node();
if(new_cmdbuf_node==NULL)
return -1;
cmdbuf_obj = (struct cmdbuf_obj* )new_cmdbuf_node->data;
cmdbuf_obj->module_type = input_para->module_type;
cmdbuf_obj->priority = input_para->priority;
@@ -1559,6 +1635,7 @@ static long release_cmdbuf(struct file *filp,u16 cmdbuf_id)
up(&vcmd_reserve_cmdbuf_sem[module_type]);
return 0;
}
static long release_cmdbuf_node(bi_list* list,bi_list_node*cmdbuf_node)
{
bi_list_node* new_cmdbuf_node=NULL;
@@ -1710,7 +1787,7 @@ static long link_and_run_cmdbuf(struct file *filp,struct exchange_parameter* inp
dev = &hantrovcmd_data[cmdbuf_obj->core_id];
input_para->core_id = cmdbuf_obj->core_id;
PDEBUG("filp=%p, VCMD Link CMDBUF [%d] to core [%d]\n", (void *)filp, cmdbuf_id, input_para->core_id);
PDEBUG("filp=%px, VCMD Link CMDBUF [%d] to core [%d]\n", (void *)filp, cmdbuf_id, input_para->core_id);
//set ddr address for vcmd registers copy.
if(dev->hw_version_id > HW_ID_1_0_C )
{
@@ -1953,11 +2030,11 @@ static unsigned int wait_cmdbuf_ready(struct file *filp,u16 cmdbuf_id,u32 *irq_s
check_cmdbuf_irq(dev,cmdbuf_obj,irq_status_ret),msecs_to_jiffies(500))
)
{
pr_err("vcmd_wait_queue_0 timeout");
pr_err("vcmd_wait_queue_0 timeout cmdbuf[%d]\n",cmdbuf_id);
return -ETIME;
}
PDEBUG("filp=%p, VCMD Wait CMDBUF [%d]\n", (void *)filp, cmdbuf_id);
PDEBUG("filp=%px, VCMD Wait CMDBUF [%d]\n", (void *)filp, cmdbuf_id);
return 0;
} else {
if (check_mc_cmdbuf_irq(filp, cmdbuf_obj, irq_status_ret))
@@ -2096,7 +2173,7 @@ long hantrovcmd_ioctl(struct file *filp,
ret = reserve_cmdbuf(filp,&input_para);
if (ret == 0)
copy_to_user((struct exchange_parameter*)arg,&input_para,sizeof(struct exchange_parameter));
PDEBUG("filp=%p, VCMD Reserve CMDBUF [%d]\n", (void *)filp, input_para.cmdbuf_id);
PDEBUG("filp=%px, VCMD Reserve CMDBUF [%d] remain %d \n", (void *)filp, input_para.cmdbuf_id,cmdbuf_used_residual);
return ret;
}
@@ -2106,7 +2183,7 @@ long hantrovcmd_ioctl(struct file *filp,
long retVal;
copy_from_user(&input_para,(struct exchange_parameter*)arg,sizeof(struct exchange_parameter));
PDEBUG("filp=%p,VCMD link and run cmdbuf,[%d] \n",(void *)filp, input_para.cmdbuf_id);
PDEBUG("filp=%px,VCMD link and run cmdbuf,[%d] \n",(void *)filp, input_para.cmdbuf_id);
if (process_manager_obj)
process_manager_obj->pm_count++;
@@ -2126,11 +2203,11 @@ long hantrovcmd_ioctl(struct file *filp,
__get_user(cmdbuf_id, (u16*)arg);
/*high 16 bits are core id, low 16 bits are cmdbuf_id*/
PDEBUG("filp=%p,VCMD wait for CMDBUF finishing. %d,\n",filp,cmdbuf_id);
PDEBUG("filp=%px,VCMD wait for CMDBUF finishing. %d,\n",filp,cmdbuf_id);
//TODO
tmp = wait_cmdbuf_ready(filp,cmdbuf_id,&irq_status_ret);
PDEBUG("filp=%p,VCMD wait for CMDBUF finished. %d,\n",filp,cmdbuf_id);
PDEBUG("filp=%px,VCMD wait for CMDBUF finished. %d,\n",filp,cmdbuf_id);
cmdbuf_id=(u16)irq_status_ret;
if (tmp==0)
{
@@ -2151,11 +2228,11 @@ long hantrovcmd_ioctl(struct file *filp,
__get_user(cmdbuf_id, (u16*)arg);
/*16 bits are cmdbuf_id*/
PDEBUG("filp=%p,VCMD release CMDBUF ,%d\n",filp,cmdbuf_id);
if (process_manager_obj)
process_manager_obj->pm_count--;
release_cmdbuf(filp,cmdbuf_id);
PDEBUG("filp=%px,VCMD release CMDBUF ,%d,remain %d \n",filp,cmdbuf_id,cmdbuf_used_residual);
return 0;
break;
}
@@ -2403,7 +2480,7 @@ int hantrovcmd_open(struct inode *inode, struct file *filp)
filp->private_data = process_manager_node->data;
PDEBUG("dev opened\n");
PDEBUG("process node %p for filp opened %p\n", (void *)process_manager_node, (void *)filp);
PDEBUG("process node %px for filp opened %px\n", (void *)process_manager_node, (void *)filp);
return result;
}
@@ -2422,7 +2499,7 @@ int hantrovcmd_release(struct inode *inode, struct file *filp)
unsigned long flags;
long retVal=0;
PDEBUG("dev closed for process %p via hantrovcmd_release\n", (void *)filp);
PDEBUG("dev closed for process %px via hantrovcmd_release\n", (void *)filp);
down(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]);
for (core_id = 0;core_id < total_vcmd_core_num; core_id++)
@@ -2436,8 +2513,13 @@ int hantrovcmd_release(struct inode *inode, struct file *filp)
if(new_cmdbuf_node==NULL)
break;
cmdbuf_obj_temp=(struct cmdbuf_obj*)new_cmdbuf_node->data;
PDEBUG("Process %p is releasing: checking cmdbuf %d of process %p.\n",
filp, cmdbuf_obj_temp->cmdbuf_id, cmdbuf_obj_temp->filp);
if(cmdbuf_obj_temp->cmdbuf_id > 1)
{
PDEBUG("Process %px is releasing: checking cmdbuf %d (done %d,linked %d wstat %d) process %px. remain %d\n",
filp, cmdbuf_obj_temp->cmdbuf_id, cmdbuf_obj_temp->cmdbuf_run_done,cmdbuf_obj_temp->cmdbuf_data_linked,
dev[core_id].working_state,
cmdbuf_obj_temp->filp,cmdbuf_used_residual);
}
if (dev[core_id].hwregs && (cmdbuf_obj_temp->filp == filp))
{
if(cmdbuf_obj_temp->cmdbuf_run_done)
@@ -2473,105 +2555,122 @@ int hantrovcmd_release(struct inode *inode, struct file *filp)
bi_list_node* done_cmdbuf_node = NULL;
int abort_cmdbuf_id;
int loop_count = 0;
//abort the vcmd and wait
pr_info("Abort due to linked cmdbuf %d of current process.\n", cmdbuf_obj_temp->cmdbuf_id);
printk_vcmd_register_debug((const void *)dev->hwregs, "Before trigger to 0");
// disable abort interrupt
//vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT_EN,0);
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_START_TRIGGER,0);
vcmd_aborted = 1;
printk_vcmd_register_debug((const void *)dev->hwregs,"After trigger to 0");
// Wait vcmd core aborted and vcmd enters IDLE mode.
//while (dev[core_id].working_state != WORKING_STATE_IDLE) {
while (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_WORK_STATE)) {
loop_count++;
if (!(loop_count % 10)) {
u32 irq_status = vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
pr_err("hantrovcmd: expected idle state, but irq status = 0x%0x\n", irq_status);
pr_err("hantrovcmd: vcmd current status is %d\n", vcmd_get_register_value((const void *)dev->hwregs, dev[core_id].reg_mirror, HWIF_VCMD_WORK_STATE));
}
mdelay(10); // wait 10ms
if (loop_count > 100) { // too long
pr_err("hantrovcmd: too long before vcmd core to IDLE state\n");
spin_unlock_irqrestore(dev[core_id].spinlock, flags);
pm_runtime_mark_last_busy(&dev[0].pdev->dev);
pm_runtime_put_sync_suspend(&dev[0].pdev->dev);
up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]);
return -ERESTARTSYS;
}
u32 irq_status_ret;
spin_unlock_irqrestore(dev[core_id].spinlock, flags);
if(wait_event_timeout(*dev[core_id].wait_queue,
check_cmdbuf_irq(dev,cmdbuf_obj_temp,&irq_status_ret),msecs_to_jiffies(1000))
)
{
spin_lock_irqsave(dev[core_id].spinlock, flags);
PDEBUG(" ## wait got cmdbuf[%d] done %d \n",cmdbuf_obj_temp->cmdbuf_id,cmdbuf_obj_temp->cmdbuf_run_done);
cmdbuf_obj_temp->cmdbuf_need_remove=1;
retVal=release_cmdbuf_node(&dev[core_id].list_manager,new_cmdbuf_node);
if(retVal==1)
cmdbuf_obj_temp->process_manager_obj = NULL;
}
dev[core_id].working_state = WORKING_STATE_IDLE;
// clear interrupt & restore abort_e
if (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT)) {
PDEBUG("Abort interrupt triggered, now clear it to avoid abort int...\n");
vcmd_write_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, 0x1<<4);
PDEBUG("Now irq status = 0x%0x.\n", vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET));
}
//printk_vcmd_register_debug((const void *)dev->hwregs, "vcmd status to IDLE");
else
{
spin_lock_irqsave(dev[core_id].spinlock, flags);
//abort the vcmd and wait
pr_info("Abort due to linked cmdbuf %d of current process.\n", cmdbuf_obj_temp->cmdbuf_id);
printk_vcmd_register_debug((const void *)dev->hwregs, "Before trigger to 0");
// disable abort interrupt
//vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT_EN,0);
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_START_TRIGGER,0);
vcmd_aborted = 1;
abort_cmdbuf_id = vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID);
PDEBUG("Abort when executing cmd buf %d.\n", abort_cmdbuf_id);
dev[core_id].sw_cmdbuf_rdy_num = 0;
dev[core_id].duration_without_int = 0;
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_EXE_CMDBUF_COUNT,0);
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_RDY_CMDBUF_COUNT,0);
printk_vcmd_register_debug((const void *)dev->hwregs,"After trigger to 0");
// Wait vcmd core aborted and vcmd enters IDLE mode.
//while (dev[core_id].working_state != WORKING_STATE_IDLE) {
while (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_WORK_STATE)) {
loop_count++;
if (!(loop_count % 10)) {
u32 irq_status = vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
pr_err("hantrovcmd: expected idle state, but irq status = 0x%0x\n", irq_status);
pr_err("hantrovcmd: vcmd current status is %d\n", vcmd_get_register_value((const void *)dev->hwregs, dev[core_id].reg_mirror, HWIF_VCMD_WORK_STATE));
}
mdelay(50); // wait 10ms
if (loop_count > 100) { // too long
pr_err("hantrovcmd: too long before vcmd core to IDLE state\n");
/* Mark cmdbuf_run_done to 1 for all the cmd buf executed. */
done_cmdbuf_node = dev[core_id].list_manager.head;
while (done_cmdbuf_node) {
if (!((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done) {
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done = 1;
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_data_linked = 0;
PDEBUG("Set cmdbuf [%d] cmdbuf_run_done to 1.\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
}
if (((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id == abort_cmdbuf_id)
break;
done_cmdbuf_node = done_cmdbuf_node->next;
}
if (cmdbuf_obj_temp->cmdbuf_run_done) {
/* current cmdbuf is in fact has been executed, but due to interrupt is not triggered, the status is not updated.
Just delink and remove it from the list. */
if (done_cmdbuf_node && done_cmdbuf_node->data) {
PDEBUG("done_cmdbuf_node is cmdbuf [%d].\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
}
if (done_cmdbuf_node) {
done_cmdbuf_node = done_cmdbuf_node->next;
if (done_cmdbuf_node)
restart_cmdbuf = (struct cmdbuf_obj*)done_cmdbuf_node->data;
}
if (restart_cmdbuf) {
PDEBUG("Set restart cmdbuf [%d] via if.\n", restart_cmdbuf->cmdbuf_id);
}
} else {
last_cmdbuf_node = new_cmdbuf_node;
/* cmd buf num from aborted cmd buf to current cmdbuf_obj_temp */
if (cmdbuf_obj_temp->cmdbuf_id != abort_cmdbuf_id) {
last_cmdbuf_node = new_cmdbuf_node->previous;
while (last_cmdbuf_node &&
((struct cmdbuf_obj*)last_cmdbuf_node->data)->cmdbuf_id != abort_cmdbuf_id) {
restart_cmdbuf = (struct cmdbuf_obj*)last_cmdbuf_node->data;
last_cmdbuf_node = last_cmdbuf_node->previous;
dev[core_id].sw_cmdbuf_rdy_num++;
dev[core_id].duration_without_int += restart_cmdbuf->executing_time;
PDEBUG("Keep valid cmdbuf [%d] in the list.\n", restart_cmdbuf->cmdbuf_id);
spin_unlock_irqrestore(dev[core_id].spinlock, flags);
pm_runtime_mark_last_busy(&dev[0].pdev->dev);
pm_runtime_put_sync_suspend(&dev[0].pdev->dev);
up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]);
return -ERESTARTSYS;
}
}
}
if (restart_cmdbuf) {
PDEBUG("Set restart cmdbuf [%d] via else.\n", restart_cmdbuf->cmdbuf_id);
}
}
dev[core_id].working_state = WORKING_STATE_IDLE;
// clear interrupt & restore abort_e
if (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT)) {
PDEBUG("Abort interrupt triggered, now clear it to avoid abort int...\n");
vcmd_write_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, 0x1<<4);
PDEBUG("Now irq status = 0x%0x.\n", vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET));
}
//printk_vcmd_register_debug((const void *)dev->hwregs, "vcmd status to IDLE");
// remove first linked cmdbuf from list
vcmd_delink_rm_cmdbuf(&dev[core_id], new_cmdbuf_node);
abort_cmdbuf_id = vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID);
PDEBUG("Abort when executing cmd buf %d.\n", abort_cmdbuf_id);
dev[core_id].sw_cmdbuf_rdy_num = 0;
dev[core_id].duration_without_int = 0;
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_EXE_CMDBUF_COUNT,0);
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_RDY_CMDBUF_COUNT,0);
/* Mark cmdbuf_run_done to 1 for all the cmd buf executed. */
done_cmdbuf_node = dev[core_id].list_manager.head;
while (done_cmdbuf_node) {
if (!((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done) {
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done = 1;
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_data_linked = 0;
PDEBUG("Set cmdbuf [%d] cmdbuf_run_done to 1.\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
}
if (((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id == abort_cmdbuf_id)
break;
done_cmdbuf_node = done_cmdbuf_node->next;
}
if (cmdbuf_obj_temp->cmdbuf_run_done) {
/* current cmdbuf is in fact has been executed, but due to interrupt is not triggered, the status is not updated.
Just delink and remove it from the list. */
if (done_cmdbuf_node && done_cmdbuf_node->data) {
PDEBUG("done_cmdbuf_node is cmdbuf [%d].\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
}
if (done_cmdbuf_node) {
done_cmdbuf_node = done_cmdbuf_node->next;
if (done_cmdbuf_node)
restart_cmdbuf = (struct cmdbuf_obj*)done_cmdbuf_node->data;
}
if (restart_cmdbuf) {
PDEBUG("Set restart cmdbuf [%d] via if.\n", restart_cmdbuf->cmdbuf_id);
}
} else {
last_cmdbuf_node = new_cmdbuf_node;
/* cmd buf num from aborted cmd buf to current cmdbuf_obj_temp */
if (cmdbuf_obj_temp->cmdbuf_id != abort_cmdbuf_id) {
last_cmdbuf_node = new_cmdbuf_node->previous;
while (last_cmdbuf_node &&
((struct cmdbuf_obj*)last_cmdbuf_node->data)->cmdbuf_id != abort_cmdbuf_id) {
restart_cmdbuf = (struct cmdbuf_obj*)last_cmdbuf_node->data;
last_cmdbuf_node = last_cmdbuf_node->previous;
dev[core_id].sw_cmdbuf_rdy_num++;
dev[core_id].duration_without_int += restart_cmdbuf->executing_time;
PDEBUG("Keep valid cmdbuf [%d] in the list.\n", restart_cmdbuf->cmdbuf_id);
}
}
if (restart_cmdbuf) {
PDEBUG("Set restart cmdbuf [%d] via else.\n", restart_cmdbuf->cmdbuf_id);
}
}
// remove first linked cmdbuf from list
vcmd_delink_rm_cmdbuf(&dev[core_id], new_cmdbuf_node);
}
}
release_cmdbuf_num++;
PDEBUG("release reserved cmdbuf\n");
PDEBUG("release reserved cmdbuf,remain %d\n",cmdbuf_used_residual);
} else if (vcmd_aborted && !cmdbuf_obj_temp->cmdbuf_run_done) {
/* VCMD is aborted, need to re-calculate the duration_without_int */
if (!restart_cmdbuf)
@@ -2630,7 +2729,12 @@ int hantrovcmd_release(struct inode *inode, struct file *filp)
}
if(release_cmdbuf_num)
wake_up_interruptible_all(&vcmd_cmdbuf_memory_wait);
wake_up_all(&vcmd_cmdbuf_memory_wait);
// free reserved but unlinkd node
// Here is powerfull free all this process reserved/linked cmdbuf
free_cmdbuf_not_linked_by_flip(filp);
spin_lock_irqsave(&vcmd_process_manager_lock, flags);
process_manager_node = global_process_manager.head;
while(1)
@@ -2642,10 +2746,10 @@ int hantrovcmd_release(struct inode *inode, struct file *filp)
break;
process_manager_node = process_manager_node->next;
}
//remove node from list
PDEBUG("process node %p for filp to be removed: %p\n", (void *)process_manager_node, (void *)process_manager_obj->filp);
PDEBUG("process node %px for filp to be removed: %px remain %d\n", (void *)process_manager_node, (void *)process_manager_obj->filp,cmdbuf_used_residual);
bi_list_remove_node(&global_process_manager,process_manager_node);
spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
free_process_manager_node(process_manager_node);
@@ -3140,7 +3244,7 @@ static void read_main_module_all_registers(u32 main_module_type)
//msleep(1000);
hantrovcmd_isr(input_para.core_id, &hantrovcmd_data[input_para.core_id]);
wait_cmdbuf_ready(NULL,input_para.cmdbuf_id,&irq_status_ret);
decoder_devfreq_record_idle( decoder_get_devfreq_priv_data() );
pr_info("%s:record_idle:busy_count = %d\n",__func__,decoder_get_devfreq_priv_data()->busy_count);
status_base_virt_addr=vcmd_status_buf_mem_pool.virtualAddress + input_para.cmdbuf_id*CMDBUF_MAX_SIZE/4+(vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_main_addr/2/4+0);
pr_info("vc8000_vcmd_driver: main module register 0:0x%x\n",*status_base_virt_addr);
pr_info("vc8000_vcmd_driver: main module register 50:0x%08x\n",*(status_base_virt_addr+50));
@@ -3293,6 +3397,7 @@ int hantrovcmd_init(struct platform_device *pdev)
cmdbuf_used_pos=1;
cmdbuf_used[0]=1;
cmdbuf_used_residual -=1;
pr_info(" CMDBUF[0] reserved,remain %d\n",cmdbuf_used_residual);
create_kernel_process_manager();
for(i=0;i<MAX_VCMD_TYPE;i++)
@@ -3618,7 +3723,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
if(new_cmdbuf_node==NULL)
{
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
spin_unlock_irqrestore(dev->spinlock, flags);
return IRQ_HANDLED;
}
@@ -3681,7 +3786,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
if(new_cmdbuf_node==NULL)
{
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
spin_unlock_irqrestore(dev->spinlock, flags);
return IRQ_HANDLED;
}
@@ -3754,7 +3859,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
if(new_cmdbuf_node==NULL)
{
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
spin_unlock_irqrestore(dev->spinlock, flags);
return IRQ_HANDLED;
}
@@ -3823,7 +3928,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
if(new_cmdbuf_node==NULL)
{
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
spin_unlock_irqrestore(dev->spinlock, flags);
return IRQ_HANDLED;
}
@@ -3896,7 +4001,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
if(new_cmdbuf_node==NULL)
{
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
spin_unlock_irqrestore(dev->spinlock, flags);
return IRQ_HANDLED;
}
@@ -3967,7 +4072,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
if(new_cmdbuf_node==NULL)
{
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
spin_unlock_irqrestore(dev->spinlock, flags);
return IRQ_HANDLED;
}

View File

@@ -634,7 +634,7 @@ struct cmdbuf_obj
u16 cmdbuf_id; //used to manage CMDBUF in driver.It is a handle to identify cmdbuf.also is an interrupt vector.position in pool,same as status position.
u8 cmdbuf_data_loaded; //0 means sw has not copied data into this CMDBUF; 1 means sw has copied data into this CMDBUF
u8 cmdbuf_data_linked; //0 :not linked, 1:linked.into a vcmd core list.
u8 cmdbuf_run_done; //if 0,waiting for CMDBUF finish; if 1, op code in CMDBUF has finished one by one. HANTRO_VCMD_IOCH_WAIT_CMDBUF will check this variable.
volatile u8 cmdbuf_run_done; //if 0,waiting for CMDBUF finish; if 1, op code in CMDBUF has finished one by one. HANTRO_VCMD_IOCH_WAIT_CMDBUF will check this variable.
u8 cmdbuf_need_remove; // if 0, not need to remove CMDBUF; 1 CMDBUF can be removed if it is not the last CMDBUF;
u8 has_end_cmdbuf; //if 1, the last opcode is end opCode.
u8 no_normal_int_cmdbuf; //if 1, JMP will not send normal interrupt.
@@ -930,8 +930,47 @@ static void free_cmdbuf_mem(u16 cmdbuf_id )
spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
cmdbuf_used[cmdbuf_id]=0;
cmdbuf_used_residual +=1;
PDEBUG(" ## real free cmdbuf[%d]\n",cmdbuf_id);
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
wake_up_interruptible_all(&vcmd_cmdbuf_memory_wait);
wake_up_all(&vcmd_cmdbuf_memory_wait);
}
static void free_cmdbuf_not_linked_by_flip(struct file *filp)
{
unsigned long flags;
int i;
struct cmdbuf_obj* cmdbuf_obj;
bi_list_node* new_cmdbuf_node;
bool freed_flag = false;
spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
for(i = 0; i < TOTAL_DISCRETE_CMDBUF_NUM; i++)
{
if(cmdbuf_used[i] && global_cmdbuf_node[i] != NULL)
{
new_cmdbuf_node = global_cmdbuf_node[i];
if(new_cmdbuf_node == 0x55555555)
{
continue;
}
cmdbuf_obj = (struct cmdbuf_obj* )new_cmdbuf_node->data;
if(cmdbuf_obj->filp == filp && !cmdbuf_obj->cmdbuf_data_linked && !cmdbuf_obj->cmdbuf_run_done)
{
cmdbuf_used[i]=0;
cmdbuf_used_residual +=1;
global_cmdbuf_node[i] = NULL;
freed_flag = true;
PDEBUG(" ## Find left node not freed,real free cmdbuf[%d],remain %d\n",i,cmdbuf_used_residual);
}
}
if(cmdbuf_used_residual >= (TOTAL_DISCRETE_CMDBUF_NUM-2))
break;
}
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
if(freed_flag)
wake_up_all(&vcmd_cmdbuf_memory_wait);
}
static bi_list_node* create_cmdbuf_node(void)
@@ -941,8 +980,13 @@ static bi_list_node* create_cmdbuf_node(void)
struct noncache_mem new_cmdbuf_addr;
struct noncache_mem new_status_cmdbuf_addr;
if(wait_event_interruptible(vcmd_cmdbuf_memory_wait, allocate_cmdbuf(&new_cmdbuf_addr,&new_status_cmdbuf_addr)) )
if(!wait_event_interruptible_timeout(vcmd_cmdbuf_memory_wait, allocate_cmdbuf(&new_cmdbuf_addr,&new_status_cmdbuf_addr),
msecs_to_jiffies(500)) )
{
pr_err("vc8000e: wait allocate_cmdbuf timeout\n");
return NULL;
}
cmdbuf_obj = create_vcmd_cmdbuf_obj(new_cmdbuf_addr.cmdbuf_id);
if(cmdbuf_obj==NULL)
{
@@ -1048,18 +1092,21 @@ static u32 calculate_executing_time_after_node_high_priority(bi_list_node* exe_c
}
return time_run_all;
}
#ifdef DEBUG_CMDBUF_ALLOC
int cmdbuf_node_unexpected[TOTAL_DISCRETE_CMDBUF_NUM];
#endif
/**********************************************************************************************************\
*cmdbuf pool management
\***********************************************************************************************************/
static int allocate_cmdbuf(struct noncache_mem* new_cmdbuf_addr,struct noncache_mem* new_status_cmdbuf_addr)
{
unsigned long flags;
u16 cmdbuf_used_pos_start = cmdbuf_used_pos;
spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
if(cmdbuf_used_residual==0)
{
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
pr_err("%s:vc8000e:no empty cmdbuf\n",__func__);
//no empty cmdbuf
return 0;
}
@@ -1080,6 +1127,7 @@ static int allocate_cmdbuf(struct noncache_mem* new_cmdbuf_addr,struct noncache
new_status_cmdbuf_addr->mmu_bus_address=vcmd_status_buf_mem_pool.mmu_bus_address + cmdbuf_used_pos*CMDBUF_MAX_SIZE;
new_status_cmdbuf_addr->size=CMDBUF_MAX_SIZE;
new_status_cmdbuf_addr->cmdbuf_id = cmdbuf_used_pos;
global_cmdbuf_node[cmdbuf_used_pos]=0x55555555; //temp set it,for another thread not hit cmdbuf_used[x] set but global_cmdbuf_node[x] is null
cmdbuf_used_pos++;
if(cmdbuf_used_pos>=TOTAL_DISCRETE_CMDBUF_NUM)
cmdbuf_used_pos=0;
@@ -1088,11 +1136,30 @@ static int allocate_cmdbuf(struct noncache_mem* new_cmdbuf_addr,struct noncache
}
else
{
#ifdef DEBUG_CMDBUF_ALLOC
if(cmdbuf_used[cmdbuf_used_pos]==0 && (global_cmdbuf_node[cmdbuf_used_pos]!=NULL ) && (cmdbuf_node_unexpected[cmdbuf_used_pos] == 0x55))
{
pr_warn("vc8000e:unexpected cmdbuf_used[%d] is 0,but global_cmdbuf_node[%d] != NULL\n",
cmdbuf_used_pos,cmdbuf_used_pos);
cmdbuf_node_unexpected[cmdbuf_used_pos] = 0x55;
}
else if(cmdbuf_used[cmdbuf_used_pos]!=0 && (global_cmdbuf_node[cmdbuf_used_pos] == NULL ) && (cmdbuf_node_unexpected[cmdbuf_used_pos] == 0x55))
{
pr_warn("vc8000e:unexpected cmdbuf_used[%d] != 0,but global_cmdbuf_node[%d] is NULL\n",
cmdbuf_used_pos,cmdbuf_used_pos);
cmdbuf_node_unexpected[cmdbuf_used_pos] = 0x55;
}
#endif
cmdbuf_used_pos++;
if(cmdbuf_used_pos>=TOTAL_DISCRETE_CMDBUF_NUM)
cmdbuf_used_pos=0;
if(cmdbuf_used_pos_start == cmdbuf_used_pos) //searched all,not find one,should return;
break;
}
}
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
pr_err("%s:vc8000e: no cmdbuf found,cmdbuf_used_residual %d\n",__func__,cmdbuf_used_residual);
return 0;
}
@@ -1493,8 +1560,13 @@ static long reserve_cmdbuf(struct file *filp,struct exchange_parameter* input_pa
spin_lock_irqsave(&process_manager_obj->spinlock, flags);
process_manager_obj->total_exe_time += input_para->executing_time;
spin_unlock_irqrestore(&process_manager_obj->spinlock, flags);
if(wait_event_interruptible(process_manager_obj->wait_queue, wait_process_resource_rdy(process_manager_obj)))
return -1;
if(!wait_event_interruptible_timeout(process_manager_obj->wait_queue, wait_process_resource_rdy(process_manager_obj),
msecs_to_jiffies(500) ))
{
pr_err("vc8000e: wait_process_resource_rdy timeout! total_exe_time %lld\n",process_manager_obj->total_exe_time);
return -1;
}
new_cmdbuf_node=create_cmdbuf_node();
if(new_cmdbuf_node==NULL)
@@ -1728,7 +1800,7 @@ static long link_and_run_cmdbuf(struct file *filp,struct exchange_parameter* inp
dev = &hantrovcmd_data[cmdbuf_obj->core_id];
input_para->core_id = cmdbuf_obj->core_id;
PDEBUG("Allocate cmd buffer [%d] to core [%d]\n", cmdbuf_id, input_para->core_id);
PDEBUG("filp=%px, VCMD Link CMDBUF [%d] to core [%d]\n", (void *)filp, cmdbuf_id, input_para->core_id);
//set ddr address for vcmd registers copy.
if(dev->hw_version_id > HW_ID_1_0_C )
{
@@ -1937,7 +2009,7 @@ static unsigned int wait_cmdbuf_ready(struct file *filp,u16 cmdbuf_id,u32 *irq_s
check_cmdbuf_irq(dev,cmdbuf_obj,irq_status_ret), msecs_to_jiffies(500) )
)
{
pr_err("vcmd_wait_queue_0 timeout\n");
pr_err("vc8000e:vcmd_wait_queue_0 timeout cmdbuf[%d]\n",cmdbuf_id);
//abort the vcmd
vcmd_write_register_value((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_START_TRIGGER,0);
return -ETIME;
@@ -1952,7 +2024,7 @@ bool hantrovcmd_devfreq_check_state(void)
u32 state = 0;
for (core_id = 0;core_id < total_vcmd_core_num; core_id++) {
state = vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_WORK_STATE);
if((state != 3) && (state != 0)) //HW state pend or idle
if((state != 0) && (state != 3) ) //HW state pend or idle
return false;
}
return true;
@@ -2078,7 +2150,7 @@ static long hantrovcmd_ioctl(struct file *filp,
ret = reserve_cmdbuf(filp,&input_para);
if (ret == 0)
copy_to_user((struct exchange_parameter*)arg,&input_para,sizeof(struct exchange_parameter));
PDEBUG(" VCMD Reserve CMDBUF %d\n", input_para.cmdbuf_id);
PDEBUG("filp=%px, VCMD Reserve CMDBUF [%d] remain %d \n", (void *)filp, input_para.cmdbuf_id,cmdbuf_used_residual);
return ret;
}
@@ -2088,7 +2160,7 @@ static long hantrovcmd_ioctl(struct file *filp,
long retVal;
copy_from_user(&input_para,(struct exchange_parameter*)arg,sizeof(struct exchange_parameter));
PDEBUG("VCMD link and run cmdbuf\n");
PDEBUG("filp=%px,VCMD link and run cmdbuf,[%d] \n",(void *)filp, input_para.cmdbuf_id);
pm_runtime_resume_and_get(dev);
if (process_manager_obj)
process_manager_obj->pm_count++;
@@ -2107,10 +2179,11 @@ static long hantrovcmd_ioctl(struct file *filp,
__get_user(cmdbuf_id, (u16*)arg);
/*high 16 bits are core id, low 16 bits are cmdbuf_id*/
PDEBUG("VCMD wait for CMDBUF finishing. \n");
PDEBUG("filp=%px,VCMD wait for CMDBUF finishing. %d,\n",filp,cmdbuf_id);
//TODO
tmp = wait_cmdbuf_ready(filp,cmdbuf_id,&irq_status_ret);
PDEBUG("filp=%px,VCMD wait for CMDBUF finished. %d,\n",filp,cmdbuf_id);
cmdbuf_id=(u16)irq_status_ret;
if (tmp==0)
{
@@ -2130,13 +2203,12 @@ static long hantrovcmd_ioctl(struct file *filp,
__get_user(cmdbuf_id, (u16*)arg);
/*16 bits are cmdbuf_id*/
PDEBUG("VCMD release CMDBUF\n");
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
if (process_manager_obj)
process_manager_obj->pm_count--;
release_cmdbuf(filp,cmdbuf_id);
PDEBUG("filp=%px,VCMD release CMDBUF ,%d,remain %d \n",filp,cmdbuf_id,cmdbuf_used_residual);
return 0;
break;
}
@@ -2388,7 +2460,7 @@ static int hantrovcmd_open(struct inode *inode, struct file *filp)
spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
filp->private_data = process_manager_node->data;
PDEBUG("dev opened\n");
PDEBUG("process node %px for filp opened %px\n", (void *)process_manager_node, (void *)filp);
return result;
}
static int __hantrovcmd_release(struct inode *inode, struct file *filp)
@@ -2406,9 +2478,8 @@ static int __hantrovcmd_release(struct inode *inode, struct file *filp)
unsigned long flags;
long retVal=0;
PDEBUG("dev closed for process %p\n", (void *)filp);
if (down_interruptible(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]))
return -ERESTARTSYS;
PDEBUG("dev closed for process %px\n", (void *)filp);
down(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]); //should be wait,do not use interruptible interface
for (core_id = 0;core_id < total_vcmd_core_num; core_id++)
{
@@ -2421,6 +2492,13 @@ static int __hantrovcmd_release(struct inode *inode, struct file *filp)
if(new_cmdbuf_node==NULL)
break;
cmdbuf_obj_temp=(struct cmdbuf_obj*)new_cmdbuf_node->data;
if(cmdbuf_obj_temp->cmdbuf_id > 1)
{
PDEBUG("Process %px is releasing: checking cmdbuf %d (done %d,linked %d wstat %d) process %px. remain %d\n",
filp, cmdbuf_obj_temp->cmdbuf_id, cmdbuf_obj_temp->cmdbuf_run_done,cmdbuf_obj_temp->cmdbuf_data_linked,
dev[core_id].working_state,
cmdbuf_obj_temp->filp,cmdbuf_used_residual);
}
if (dev[core_id].hwregs && (cmdbuf_obj_temp->filp == filp))
{
if(cmdbuf_obj_temp->cmdbuf_run_done)
@@ -2451,111 +2529,127 @@ static int __hantrovcmd_release(struct inode *inode, struct file *filp)
bi_list_node* done_cmdbuf_node = NULL;
int abort_cmdbuf_id;
int loop_count = 0;
u32 irq_status_ret;
//abort the vcmd and wait
PDEBUG("Abort due to linked cmdbuf %d of current process.\n", cmdbuf_obj_temp->cmdbuf_id);
#ifdef VCMD_DEBUG_INTERNAL
printk_vcmd_register_debug((const void *)dev[core_id].hwregs, "Before trigger to 0");
#endif
// disable abort interrupt
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_START_TRIGGER,0);
vcmd_aborted = 1;
software_triger_abort = 1;
#ifdef VCMD_DEBUG_INTERNAL
printk_vcmd_register_debug((const void *)dev[core_id].hwregs,"After trigger to 0");
#endif
// wait vcmd core aborted and vcmd enters IDLE mode.
while (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_WORK_STATE)) {
loop_count++;
if (!(loop_count % 10)) {
u32 irq_status = vcmd_read_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
pr_err("hantrovcmd: expected idle state, but irq status = 0x%0x\n", irq_status);
pr_err("hantrovcmd: vcmd current status is %d\n", vcmd_get_register_value((const void *)dev[core_id].hwregs, dev[core_id].reg_mirror, HWIF_VCMD_WORK_STATE));
}
mdelay(10); // wait 10ms
if (loop_count > 100) { // too long
pr_err("hantrovcmd: too long before vcmd core to IDLE state\n");
process_manager_obj = (struct process_manager_obj*)filp->private_data;
if (process_manager_obj)
{
while(process_manager_obj->pm_count > 0)
{
pm_runtime_mark_last_busy(&dev[0].pdev->dev);
pm_runtime_put_autosuspend(&dev[0].pdev->dev);
process_manager_obj->pm_count--;
spin_unlock_irqrestore(dev[core_id].spinlock, flags);
if(wait_event_timeout(*dev[core_id].wait_queue,
check_cmdbuf_irq(dev,cmdbuf_obj_temp,&irq_status_ret),msecs_to_jiffies(1000))
)
{
spin_lock_irqsave(dev[core_id].spinlock, flags);
PDEBUG(" ## wait got cmdbuf[%d] done %d \n",cmdbuf_obj_temp->cmdbuf_id,cmdbuf_obj_temp->cmdbuf_run_done);
cmdbuf_obj_temp->cmdbuf_need_remove=1;
retVal=release_cmdbuf_node(&dev[core_id].list_manager,new_cmdbuf_node);
if(retVal==1)
cmdbuf_obj_temp->process_manager_obj = NULL;
}
else
{
//abort the vcmd and wait
PDEBUG("Abort due to linked cmdbuf %d of current process.\n", cmdbuf_obj_temp->cmdbuf_id);
#ifdef VCMD_DEBUG_INTERNAL
printk_vcmd_register_debug((const void *)dev[core_id].hwregs, "Before trigger to 0");
#endif
// disable abort interrupt
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_START_TRIGGER,0);
vcmd_aborted = 1;
software_triger_abort = 1;
#ifdef VCMD_DEBUG_INTERNAL
printk_vcmd_register_debug((const void *)dev[core_id].hwregs,"After trigger to 0");
#endif
// wait vcmd core aborted and vcmd enters IDLE mode.
while (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_WORK_STATE)) {
loop_count++;
if (!(loop_count % 10)) {
u32 irq_status = vcmd_read_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
pr_err("hantrovcmd: expected idle state, but irq status = 0x%0x\n", irq_status);
pr_err("hantrovcmd: vcmd current status is %d\n", vcmd_get_register_value((const void *)dev[core_id].hwregs, dev[core_id].reg_mirror, HWIF_VCMD_WORK_STATE));
}
mdelay(10); // wait 10ms
if (loop_count > 100) { // too long
pr_err("hantrovcmd: too long before vcmd core to IDLE state\n");
process_manager_obj = (struct process_manager_obj*)filp->private_data;
if (process_manager_obj)
{
while(process_manager_obj->pm_count > 0)
{
pm_runtime_mark_last_busy(&dev[0].pdev->dev);
pm_runtime_put_autosuspend(&dev[0].pdev->dev);
process_manager_obj->pm_count--;
}
}
spin_unlock_irqrestore(dev[core_id].spinlock, flags);
up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]);
return -ERESTARTSYS;
}
}
spin_unlock_irqrestore(dev[core_id].spinlock, flags);
up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]);
return -ERESTARTSYS;
}
}
dev[core_id].working_state = WORKING_STATE_IDLE;
// clear interrupt & restore abort_e
if (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT)) {
PDEBUG("Abort interrupt triggered, now clear it to avoid abort int...\n");
vcmd_write_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, 0x1<<4);
PDEBUG("Now irq status = 0x%0x.\n", vcmd_read_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET));
}
abort_cmdbuf_id = vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID);
PDEBUG("Abort when executing cmd buf %d.\n", abort_cmdbuf_id);
dev[core_id].sw_cmdbuf_rdy_num = 0;
dev[core_id].duration_without_int = 0;
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_EXE_CMDBUF_COUNT,0);
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_RDY_CMDBUF_COUNT,0);
/* Mark cmdbuf_run_done to 1 for all the cmd buf executed. */
done_cmdbuf_node = dev[core_id].list_manager.head;
while (done_cmdbuf_node) {
if (!((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done) {
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done = 1;
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_data_linked = 0;
PDEBUG("Set cmdbuf [%d] cmdbuf_run_done to 1.\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
}
if (((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id == abort_cmdbuf_id)
break;
done_cmdbuf_node = done_cmdbuf_node->next;
}
if (cmdbuf_obj_temp->cmdbuf_run_done) {
/* current cmdbuf is in fact has been executed, but due to interrupt is not triggered, the status is not updated.
Just delink and remove it from the list. */
if (done_cmdbuf_node && done_cmdbuf_node->data) {
PDEBUG("done_cmdbuf_node is cmdbuf [%d].\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
}
done_cmdbuf_node = done_cmdbuf_node->next;
if (done_cmdbuf_node)
restart_cmdbuf = (struct cmdbuf_obj*)done_cmdbuf_node->data;
if (restart_cmdbuf) {
PDEBUG("Set restart cmdbuf [%d] via if.\n", restart_cmdbuf->cmdbuf_id);
}
} else {
last_cmdbuf_node = new_cmdbuf_node;
/* cmd buf num from aborted cmd buf to current cmdbuf_obj_temp */
if (cmdbuf_obj_temp->cmdbuf_id != abort_cmdbuf_id) {
last_cmdbuf_node = new_cmdbuf_node->previous;
while (last_cmdbuf_node &&
((struct cmdbuf_obj*)last_cmdbuf_node->data)->cmdbuf_id != abort_cmdbuf_id) {
restart_cmdbuf = (struct cmdbuf_obj*)last_cmdbuf_node->data;
last_cmdbuf_node = last_cmdbuf_node->previous;
dev[core_id].sw_cmdbuf_rdy_num++;
dev[core_id].duration_without_int += restart_cmdbuf->executing_time;
PDEBUG("Keep valid cmdbuf [%d] in the list.\n", restart_cmdbuf->cmdbuf_id);
dev[core_id].working_state = WORKING_STATE_IDLE;
// clear interrupt & restore abort_e
if (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT)) {
PDEBUG("Abort interrupt triggered, now clear it to avoid abort int...\n");
vcmd_write_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, 0x1<<4);
PDEBUG("Now irq status = 0x%0x.\n", vcmd_read_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET));
}
}
if (restart_cmdbuf) {
PDEBUG("Set restart cmdbuf [%d] via else.\n", restart_cmdbuf->cmdbuf_id);
}
}
// remove first linked cmdbuf from list
vcmd_delink_rm_cmdbuf(&dev[core_id], new_cmdbuf_node);
abort_cmdbuf_id = vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID);
PDEBUG("Abort when executing cmd buf %d.\n", abort_cmdbuf_id);
dev[core_id].sw_cmdbuf_rdy_num = 0;
dev[core_id].duration_without_int = 0;
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_EXE_CMDBUF_COUNT,0);
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_RDY_CMDBUF_COUNT,0);
/* Mark cmdbuf_run_done to 1 for all the cmd buf executed. */
done_cmdbuf_node = dev[core_id].list_manager.head;
while (done_cmdbuf_node) {
if (!((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done) {
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done = 1;
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_data_linked = 0;
PDEBUG("Set cmdbuf [%d] cmdbuf_run_done to 1.\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
}
if (((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id == abort_cmdbuf_id)
break;
done_cmdbuf_node = done_cmdbuf_node->next;
}
if (cmdbuf_obj_temp->cmdbuf_run_done) {
/* current cmdbuf is in fact has been executed, but due to interrupt is not triggered, the status is not updated.
Just delink and remove it from the list. */
if (done_cmdbuf_node && done_cmdbuf_node->data) {
PDEBUG("done_cmdbuf_node is cmdbuf [%d].\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
}
done_cmdbuf_node = done_cmdbuf_node->next;
if (done_cmdbuf_node)
restart_cmdbuf = (struct cmdbuf_obj*)done_cmdbuf_node->data;
if (restart_cmdbuf) {
PDEBUG("Set restart cmdbuf [%d] via if.\n", restart_cmdbuf->cmdbuf_id);
}
} else {
last_cmdbuf_node = new_cmdbuf_node;
/* cmd buf num from aborted cmd buf to current cmdbuf_obj_temp */
if (cmdbuf_obj_temp->cmdbuf_id != abort_cmdbuf_id) {
last_cmdbuf_node = new_cmdbuf_node->previous;
while (last_cmdbuf_node &&
((struct cmdbuf_obj*)last_cmdbuf_node->data)->cmdbuf_id != abort_cmdbuf_id) {
restart_cmdbuf = (struct cmdbuf_obj*)last_cmdbuf_node->data;
last_cmdbuf_node = last_cmdbuf_node->previous;
dev[core_id].sw_cmdbuf_rdy_num++;
dev[core_id].duration_without_int += restart_cmdbuf->executing_time;
PDEBUG("Keep valid cmdbuf [%d] in the list.\n", restart_cmdbuf->cmdbuf_id);
}
}
if (restart_cmdbuf) {
PDEBUG("Set restart cmdbuf [%d] via else.\n", restart_cmdbuf->cmdbuf_id);
}
}
// remove first linked cmdbuf from list
vcmd_delink_rm_cmdbuf(&dev[core_id], new_cmdbuf_node);
}
}
software_triger_abort = 0;
release_cmdbuf_num++;
PDEBUG("release reserved cmdbuf\n");
PDEBUG("vc8000e : release reserved cmdbuf,remain %d\n",cmdbuf_used_residual);
}
else if (vcmd_aborted && !cmdbuf_obj_temp->cmdbuf_run_done) {
/* VCMD is aborted, need to re-calculate the duration_without_int */
@@ -2618,7 +2712,12 @@ static int __hantrovcmd_release(struct inode *inode, struct file *filp)
wake_up_all(dev[core_id].wait_queue);
}
if(release_cmdbuf_num)
wake_up_interruptible_all(&vcmd_cmdbuf_memory_wait);
wake_up_all(&vcmd_cmdbuf_memory_wait);
// free reserved but unlinkd node
// Here is powerfull free all this process reserved/linked cmdbuf
free_cmdbuf_not_linked_by_flip(filp);
spin_lock_irqsave(&vcmd_process_manager_lock, flags);
process_manager_node = global_process_manager.head;
while(1)
@@ -2640,6 +2739,7 @@ static int __hantrovcmd_release(struct inode *inode, struct file *filp)
}
}
//remove node from list
PDEBUG("process node %px for filp to be removed: %px remain %d\n", (void *)process_manager_node, (void *)process_manager_obj->filp,cmdbuf_used_residual);
bi_list_remove_node(&global_process_manager,process_manager_node);
spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
free_process_manager_node(process_manager_node);
@@ -2790,7 +2890,7 @@ static u32 ConfigAXIFE(u32 mode)
#endif
if (axife_hwregs[i][0] != NULL)
{
PDEBUG("ConfigAXIFE: axife_hwregs[%d][0]=%p\n", i, axife_hwregs[i][0]);
PDEBUG("ConfigAXIFE: axife_hwregs[%d][0]=%px\n", i, axife_hwregs[i][0]);
AXIFEEnable(axife_hwregs[i][0], mode);
}
}
@@ -2810,7 +2910,7 @@ static u32 ConfigAXIFE(u32 mode)
#endif
if (axife_hwregs[i][1] != NULL)
{
PDEBUG("ConfigAXIFE: axife_hwregs[%d][1]=%p\n", i, axife_hwregs[i][1]);
PDEBUG("ConfigAXIFE: axife_hwregs[%d][1]=%px\n", i, axife_hwregs[i][1]);
AXIFEEnable(axife_hwregs[i][1] , mode);
}
}
@@ -2858,7 +2958,7 @@ static u32 ConfigMMU(void)
}
else
pr_info("MMU detected!\n");
PDEBUG("mmu_hwregs[%d][0]=%p\n", i, mmu_hwregs[i][0]);
PDEBUG("mmu_hwregs[%d][0]=%px\n", i, mmu_hwregs[i][0]);
}
}
@@ -2876,7 +2976,7 @@ static u32 ConfigMMU(void)
mmu_hwregs[i][1] = (volatile u8*)ioremap(vcmd_core_array[i].vcmd_base_addr
+vcmd_core_array[i].submodule_MMU_addr[1], MMU_SIZE);
#endif
PDEBUG("mmu_hwregs[%d][1]=%p\n", i, mmu_hwregs[i][1]);
PDEBUG("mmu_hwregs[%d][1]=%px\n", i, mmu_hwregs[i][1]);
}
}
mmu_status = MMUEnable(mmu_hwregs);
@@ -3492,7 +3592,8 @@ static void read_main_module_all_registers(u32 main_module_type)
//msleep(1000);
hantrovcmd_isr(input_para.core_id, &hantrovcmd_data[input_para.core_id]);
wait_cmdbuf_ready(NULL,input_para.cmdbuf_id,&irq_status_ret);
encoder_devfreq_record_idle( encoder_get_devfreq_priv_data() );
pr_info("%s:record_idle:busy_count = %d\n",__func__,encoder_get_devfreq_priv_data()->busy_count);
status_base_virt_addr=vcmd_status_buf_mem_pool.virtualAddress + input_para.cmdbuf_id*CMDBUF_MAX_SIZE/4+(vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_main_addr/2/4+0);
pr_info("vc8000_vcmd_driver: main module register 0:0x%x\n",*status_base_virt_addr);
pr_info("vc8000_vcmd_driver: main module register 80:0x%x\n",*(status_base_virt_addr+80));
@@ -3869,7 +3970,7 @@ void encoder_devfreq_record_busy(struct encoder_devfreq *devfreq)
encoder_dev_clk_lock();
spin_lock_irqsave(&devfreq->lock, irqflags);
busy_count = devfreq->busy_count;
//pr_info("record_busy:busy_count = %d\n",busy_count);
PDEBUG("record_busy:busy_count = %d\n",busy_count);
if(devfreq->busy_count > 0)
{
devfreq->busy_count++;
@@ -3898,7 +3999,7 @@ void encoder_devfreq_record_idle(struct encoder_devfreq *devfreq)
return;
spin_lock_irqsave(&devfreq->lock, irqflags);
//pr_info("record_idle:busy_count = %d\n",devfreq->busy_count);
PDEBUG("record_idle:busy_count = %d\n",devfreq->busy_count);
if(devfreq->busy_count > 1)
{
devfreq->busy_count--;
@@ -4102,7 +4203,7 @@ int encoder_devfreq_init(struct device *dev)
int ret = 0;
struct encoder_devfreq *devfreq = encoder_get_devfreq_priv_data();
memset(devfreq,sizeof(struct encoder_devfreq),0);
memset(devfreq,0,sizeof(struct encoder_devfreq));
spin_lock_init(&devfreq->lock);
init_waitqueue_head(&devfreq->target_freq_wait_queue);
mutex_init(&devfreq->clk_mutex);
@@ -4486,6 +4587,7 @@ int __init hantroenc_vcmd_probe(struct platform_device *pdev)
cmdbuf_used_pos=1;
cmdbuf_used[0]=1;
cmdbuf_used_residual -=1;
pr_info(" CMDBUF[0] reserved,remain %d\n",cmdbuf_used_residual);
pr_info("vc8000_vcmd_driver: module inserted. Major <%d>\n", hantrovcmd_major);
@@ -4699,7 +4801,7 @@ static int vcmd_reserve_IO(void)
/*read hwid and check validness and store it*/
hwid = (u32)ioread32(( void *)hantrovcmd_data[i].hwregs);
pr_info("vcmd_reserve_IO: hantrovcmd_data[%d].hwregs=0x%p\n",i, hantrovcmd_data[i].hwregs);
pr_info("vcmd_reserve_IO: hantrovcmd_data[%d].hwregs=0x%px\n",i, hantrovcmd_data[i].hwregs);
pr_info("hwid=0x%08x\n", hwid);
hantrovcmd_data[i].hw_version_id = hwid;
@@ -4879,7 +4981,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
if(new_cmdbuf_node==NULL)
{
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
spin_unlock_irqrestore(dev->spinlock, flags);
return IRQ_HANDLED;
}
@@ -4951,7 +5053,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
if(new_cmdbuf_node==NULL)
{
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
spin_unlock_irqrestore(dev->spinlock, flags);
return IRQ_HANDLED;
}
@@ -5023,7 +5125,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
if(new_cmdbuf_node==NULL)
{
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
spin_unlock_irqrestore(dev->spinlock, flags);
return IRQ_HANDLED;
}
@@ -5163,7 +5265,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
if(new_cmdbuf_node==NULL)
{
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
spin_unlock_irqrestore(dev->spinlock, flags);
return IRQ_HANDLED;
}
@@ -5233,7 +5335,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
if(new_cmdbuf_node==NULL)
{
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
spin_unlock_irqrestore(dev->spinlock, flags);
return IRQ_HANDLED;
}

59
drivers/usb/dwc3/dwc3-thead.c Normal file → Executable file
View File

@@ -259,40 +259,12 @@ static int dwc3_thead_remove(struct platform_device *pdev)
static int dwc3_thead_pm_suspend(struct device *dev)
{
struct dwc3_thead *thead = dev_get_drvdata(dev);
int ret;
dwc3_thead_assert(thead);
if (!IS_ERR(thead->hubswitch)) {
ret = regulator_disable(thead->hub1v2);
if (ret) {
dev_err(dev, "failed to disable regulator hub1v2 %d\n", ret);
}
}
if (!IS_ERR(thead->hub5v)) {
ret = regulator_disable(thead->hub5v);
if (ret) {
dev_err(dev, "failed to disable regulator hub1v2 %d\n", ret);
}
}
clk_bulk_disable(thead->num_clocks, thead->clks);
ret = regulator_disable(thead->vbus);
if (ret) {
dev_err(dev, "failed to disable regulator vbus %d\n", ret);
}
ret = regulator_disable(thead->hub1v2);
if (ret) {
dev_err(dev, "failed to disable regulator hub1v2 %d\n", ret);
}
ret = regulator_disable(thead->hub5v);
if (ret) {
dev_err(dev, "failed to disable regulator hub1v2 %d\n", ret);
}
return ret;
return 0;
}
@@ -300,35 +272,6 @@ static int dwc3_thead_pm_resume(struct device *dev)
{
struct dwc3_thead *thead = dev_get_drvdata(dev);
int ret;
dev_info(dev,"%s\n",__func__);
ret = regulator_enable(thead->vbus);
if (ret) {
dev_err(dev, "failed to enable regulator vbus %d\n", ret);
}
ret = regulator_enable(thead->hub1v2);
if (ret) {
dev_err(dev, "failed to enable regulator hub1v2 %d\n", ret);
}
ret = regulator_enable(thead->hub5v);
if (ret) {
dev_err(dev, "failed to enable regulator hub1v2 %d\n", ret);
}
/* enable regulator here for some extend regulator does not have pm func */
if (!IS_ERR(thead->hub1v2)) {
ret = regulator_enable(thead->hub1v2);
if (ret) {
dev_err(dev, "failed to enable regulator hub1v2 %d\n", ret);
}
}
if (!IS_ERR(thead->hub5v)) {
ret = regulator_enable(thead->hub5v);
if (ret) {
dev_err(dev, "failed to enable regulator hub1v2 %d\n", ret);
}
}
ret = clk_bulk_prepare_enable(thead->num_clocks, thead->clks);
if (ret) {

View File

@@ -86,6 +86,7 @@
#include "video_memory.h"
#include "rsvmem_pool.h"
//#define VIDMEM_DMA_MAP
#define DISCRETE_PAGES 0
//#define VIDMEM_DEBUG
@@ -183,6 +184,7 @@
#ifndef VIDMEM_DEBUG
#define DEBUG_PRINT(...) \
do { \
pr_debug(__VA_ARGS__);\
} while (0)
#else
#undef DEBUG_PRINT
@@ -202,8 +204,9 @@ struct mem_block
struct vm_area_struct * vma;
bool is_cma;
bool is_vi_mem;
bool cache_en;
void *va;
struct file *filp;
union
{
/* Pointer to a array of pages. */
@@ -232,6 +235,7 @@ struct mem_node
struct mem_block memBlk;
unsigned long busAddr;
int isImported;
int isExported;
struct list_head link;
};
@@ -243,6 +247,9 @@ struct file_node
};
static struct list_head fileList;
/* golbal list for exported mem_node */
static struct list_head export_list;
static DEFINE_SPINLOCK(export_mem_lock);
static int vidalloc_major = 0;
static int vidalloc_minor = 0;
@@ -259,6 +266,7 @@ getPhysical(
IN unsigned int Offset,
OUT unsigned long * Physical
);
void free_memblk_pages(struct mem_block *memBlk);
static struct file_node * find_and_delete_file_node(struct file *filp)
{
@@ -298,6 +306,23 @@ static struct file_node * get_file_node(struct file *filp)
return NULL;
}
static struct mem_node * get_export_mem_node(struct file *filp, unsigned long bus_address)
{
struct mem_node *node;
spin_lock(&export_mem_lock);
list_for_each_entry(node, &export_list, link)
{
if (node->busAddr == bus_address)
{
DEBUG_PRINT("[vidmem] Found export mem node %px, %d pages\n", node);
spin_unlock(&export_mem_lock);
return node;
}
}
spin_unlock(&export_mem_lock);
return NULL;
}
static struct mem_node * get_mem_node(struct file *filp, unsigned long bus_address, int imported)
{
struct file_node *fnode;
@@ -320,6 +345,7 @@ static struct mem_node * get_mem_node(struct file *filp, unsigned long bus_addre
}
spin_unlock(&mem_lock);
return NULL;
}
@@ -441,6 +467,46 @@ OnError:
return status;
}
static void invalid_data_cache(IN struct file *filp, IN unsigned long bus_address )
{
struct mem_block *memBlk = NULL;
struct mem_node *mnode = NULL;
mnode = get_mem_node(filp, bus_address, 0);
if (NULL == mnode)
{
mnode = get_export_mem_node(filp, bus_address);
if (NULL == mnode)
return;
}
memBlk = &mnode->memBlk;
dma_addr_t dma_handle = memBlk->dma_addr;
size_t size = memBlk->size;
dma_sync_single_for_cpu(gdev,dma_handle ,memBlk->size,DMA_FROM_DEVICE);
}
static void flush_data_cache(IN struct file *filp, IN unsigned long bus_address )
{
struct mem_block *memBlk = NULL;
struct mem_node *mnode = NULL;
mnode = get_mem_node(filp, bus_address, 0);
if (NULL == mnode)
{
mnode = get_export_mem_node(filp, bus_address);
if (NULL == mnode)
return;
}
memBlk = &mnode->memBlk;
dma_addr_t dma_handle = memBlk->dma_addr;
size_t size = memBlk->size;
dma_sync_single_for_device(gdev,dma_handle ,memBlk->size,DMA_TO_DEVICE);
}
static int
Mmap(
IN struct mem_block *MemBlk,
@@ -455,16 +521,21 @@ Mmap(
vma->vm_flags |= VM_FLAGS;
/* Make this mapping write combined. */
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
if (!memBlk->cache_en) {
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
}
DEBUG_PRINT("vm_page_prot:0x%llx\n",vma->vm_page_prot);
/* Now map all the vmalloc pages to this user address. */
if (memBlk->contiguous)
{
/* map kernel memory to user space.. */
#if 0
if (memBlk->is_cma == true) {
return dma_mmap_coherent(gdev, vma, memBlk->va,
memBlk->dma_addr, vma->vm_end - vma->vm_start);
} else {
} else
#endif
{
if (remap_pfn_range(vma,
vma->vm_start,
page_to_pfn(memBlk->contiguousPages) + skipPages,
@@ -658,6 +729,29 @@ OnError:
static void _dmabuf_release(struct dma_buf *dmabuf)
{
struct mem_block *memBlk = dmabuf->priv;
unsigned long physical;
//struct mem_node *mnode = (mem_node *)memBlk;
struct mem_node *mnode = container_of(memBlk,struct mem_node,memBlk);
if (!memBlk)
return;
if(!memBlk->filp)
{
DEBUG_PRINT("[vidmem] %s, %d: memBlk filp null\n", __func__, __LINE__);
return;
}
getPhysical(memBlk, 0, &physical);
DEBUG_PRINT("[vidmem] %s, %d: free physical %llx,mnode %px\n", __func__, __LINE__,physical,mnode);
free_memblk_pages(memBlk);
DEBUG_PRINT(" %s: remove node\n",__func__);
//remove node from export gloabl list
spin_lock(&export_mem_lock);
list_del(&mnode->link);
spin_unlock(&export_mem_lock);
DEBUG_PRINT(" %s: FreeMemory of node\n",__func__);
FreeMemory(mnode);
dmabuf->priv = NULL;
}
static void *_dmabuf_kmap(struct dma_buf *dmabuf, unsigned long offset)
@@ -706,6 +800,8 @@ DMABUF_Export(
}
memBlk = &mnode->memBlk;
memBlk->filp = filp;
mnode->isExported = 1;
dmabuf = memBlk->dmabuf;
if (dmabuf == NULL)
@@ -739,8 +835,18 @@ DMABUF_Export(
}
*FD = fd;
DEBUG_PRINT(" [vidmem] Export as fd %d,mnode %px memBlk %px\n", fd,mnode,&mnode->memBlk);
}
/*exported buffer remove from list*/
spin_lock(&mem_lock);
list_del(&mnode->link);
spin_unlock(&mem_lock);
/* add to export gloabl list*/
spin_lock(&export_mem_lock);
list_add_tail(&mnode->link,&export_list);
spin_unlock(&export_mem_lock);
OnError:
return status;
}
@@ -775,7 +881,7 @@ DMABUF_Import(
}
memBlk = &mnode->memBlk;
memBlk->filp = filp;
/* Import dma buf handle. */
memBlk->dmabuf = dma_buf_get(FD);
if (!memBlk->dmabuf)
@@ -815,7 +921,7 @@ DMABUF_Release(
{
struct mem_block *memBlk = NULL;
struct mem_node *mnode = NULL;
DEBUG_PRINT("[vidmem] enter %s: bus_address 0x%lx\n",__func__, bus_address);
mnode = get_mem_node(filp, bus_address, 1);
if (NULL == mnode)
{
@@ -832,6 +938,7 @@ DMABUF_Release(
FreeMemory(memBlk->pagearray);
DEBUG_PRINT("[vidmem] release bus address at 0x%lx in size of %ld\n", bus_address, memBlk->size);
spin_lock(&mem_lock);
list_del(&mnode->link);
spin_unlock(&mem_lock);
@@ -991,6 +1098,13 @@ GFP_Alloc(
gfp |= __GFP_DMA32;
}
if (Flags & ALLOC_FLAG_ENABLE_CACHE) {
memBlk->cache_en = true;
} else {
memBlk->cache_en = false;
}
memBlk->contiguous = contiguous;
memBlk->numPages = numPages;
memBlk->size = size;
@@ -1133,7 +1247,9 @@ OnDone:
*bus_address = physical;
mnode->busAddr = physical;
mnode->isImported = 0;
spin_lock(&mem_lock);
list_add_tail(&mnode->link, &fnode->memList);
spin_unlock(&mem_lock);
DEBUG_PRINT("[vidmem] Allocated %d bytes (%ld pages) at physical address 0x%lx with %d sg table entries\n",
size, numPages, physical, contiguous ? 1 : memBlk->sgt->nents);
@@ -1154,27 +1270,11 @@ OnError:
return status;
}
void
GFP_Free(
IN struct file *filp,
IN unsigned long bus_address
)
void free_memblk_pages(struct mem_block *memBlk)
{
size_t i;
struct page * page;
struct mem_block *memBlk = NULL;
struct mem_node *mnode = NULL;
mnode = get_mem_node(filp, bus_address, 0);
if (NULL == mnode)
{
return;
}
memBlk = &mnode->memBlk;
DEBUG_PRINT("[vidmem] Free %ld pages from physical address 0x%lx\n", memBlk->numPages, mnode->busAddr);
DEBUG_PRINT(" ##[vidmem] Free %ld pages, contiguous %d\n", memBlk->numPages, memBlk->contiguous);
if (memBlk->contiguous)
{
@@ -1235,6 +1335,27 @@ GFP_Free(
{
NonContiguousFree(memBlk->nonContiguousPages, memBlk->numPages);
}
}
void
GFP_Free(
IN struct file *filp,
IN unsigned long bus_address
)
{
struct mem_block *memBlk = NULL;
struct mem_node *mnode = NULL;
mnode = get_mem_node(filp, bus_address, 0);
if (NULL == mnode)
{
return;
}
memBlk = &mnode->memBlk;
DEBUG_PRINT("[vidmem] Free %ld pages from physical address 0x%lx\n", memBlk->numPages, mnode->busAddr);
free_memblk_pages(memBlk);
spin_lock(&mem_lock);
list_del(&mnode->link);
@@ -1256,7 +1377,9 @@ GFP_MapUser(
mnode = get_mem_node(filp, bus_address, 0);
if (NULL == mnode)
{
return EINVAL;
mnode = get_export_mem_node(filp, bus_address);
if (NULL == mnode)
return EINVAL;
}
memBlk = &mnode->memBlk;
@@ -1349,6 +1472,21 @@ static long vidalloc_ioctl(struct file *filp, unsigned int cmd, unsigned long ar
}
break;
}
case MEMORY_IOC_DMABUF_FLUSH_CACHE:
ret = copy_from_user(&params, (void*)arg, sizeof(VidmemParams));
if (!ret)
{
flush_data_cache(filp, params.bus_address);
}
break;
case MEMORY_IOC_DMABUF_INVALID_CACHE:
ret = copy_from_user(&params, (void*)arg, sizeof(VidmemParams));
if (!ret)
{
invalid_data_cache(filp, params.bus_address);
}
break;
default:
ret = EINVAL;
}
@@ -1385,7 +1523,11 @@ static int vidalloc_release(struct inode *inode, struct file *filp)
list_for_each_entry_safe(node, temp, &fnode->memList, link)
{
// this is not expected, memory leak detected!
pr_debug("vidmem: Found unfreed memory at 0x%lx, isImported = %d\n", node->busAddr, node->isImported);
pr_debug("vidmem: Found unfreed memory at 0x%lx, isImported = %d isExported = %d\n", node->busAddr, node->isImported,node->isExported);
if (node->isExported) //let dmabuf release ops free
{
continue;
}
if (node->isImported)
DMABUF_Release(filp, node->busAddr);
else
@@ -1415,10 +1557,11 @@ int vidalloc_probe(struct platform_device *pdev)
{
int result = 0;
DEBUG_PRINT("enter %s\n",__func__);
pr_info("enter %s,ver:1.2A\n",__func__);
#if 1
gdev = &pdev->dev;
INIT_LIST_HEAD(&fileList);
INIT_LIST_HEAD(&export_list);
result = rsvmem_pool_create(&pdev->dev);
if (result && result != -ENODEV)

View File

@@ -37,6 +37,8 @@
#define ALLOC_FLAG_CMA 0x00000008
/* Use VI reserved memory */
#define ALLOC_FLAG_VI 0x00000010
/* Buffer enable cache */
#define ALLOC_FLAG_ENABLE_CACHE 0x00000020
/* Alloc rsvmem pool region id should be 0~15 */
#define SET_ALLOC_FLAG_REGION(flag, region_id) (flag & 0x00ffffff) | (region_id << 24)
@@ -49,7 +51,9 @@
#define MEMORY_IOC_DMABUF_EXPORT _IOWR(MEMORY_IOC_MAGIC, 3, VidmemParams *)
#define MEMORY_IOC_DMABUF_IMPORT _IOWR(MEMORY_IOC_MAGIC, 4, VidmemParams *)
#define MEMORY_IOC_DMABUF_RELEASE _IOWR(MEMORY_IOC_MAGIC, 5, VidmemParams *)
#define MEMORY_IOC_MAXNR 5
#define MEMORY_IOC_DMABUF_FLUSH_CACHE _IOWR(MEMORY_IOC_MAGIC, 6, VidmemParams *)
#define MEMORY_IOC_DMABUF_INVALID_CACHE _IOWR(MEMORY_IOC_MAGIC, 7, VidmemParams *)
#define MEMORY_IOC_MAXNR 7
typedef struct {
unsigned long bus_address;
@@ -59,4 +63,7 @@ typedef struct {
int flags;
} VidmemParams;
#endif /* __VIDEO_MEMORY_H_ */

View File

@@ -26,7 +26,6 @@
#include "video_memory.h"
#include "video_mem.h"
#define VMEM_PRINT(level, ...) \
{ \
if (log_level >= VMEM_LOG_##level) \
@@ -115,7 +114,7 @@ VMEM_allocate(void *vmem, VmemParams *params)
}
params->phy_address = p.bus_address;
VMEM_LOGI("Allocated %d bytes, phy addr 0x%08x\n",
VMEM_LOGI("Allocated %d bytes, phy addr 0x%lx\n",
params->size, params->phy_address);
return VMEM_STATUS_OK;
@@ -129,7 +128,7 @@ VMEM_mmap(void *vmem, VmemParams *params)
if (vmem == NULL || params == NULL)
return VMEM_STATUS_ERROR;
if (params->vir_address != NULL)
return VMEM_STATUS_OK;
@@ -140,13 +139,13 @@ VMEM_mmap(void *vmem, VmemParams *params)
MAP_SHARED, fd, offset);
if (vir_addr == MAP_FAILED)
{
VMEM_LOGE("Failed to mmap physical address: 0x%08x, using fd %d\n",
VMEM_LOGE("Failed to mmap physical address: 0x%lx, using fd %d\n",
params->phy_address, fd);
return VMEM_STATUS_ERROR;
}
params->vir_address = vir_addr;
VMEM_LOGI("Mapped phy addr 0x%08x to vir addr %p, size %d\n",
VMEM_LOGI("Mapped phy addr 0x%lx to vir addr %p, size %d\n",
params->phy_address, params->vir_address, params->size);
return VMEM_STATUS_OK;
@@ -163,7 +162,7 @@ VMEM_free(void *vmem, VmemParams *params)
ctx = (VmemContext *)vmem;
VMEM_LOGI("Free virt addr %p, phy addr 0x%08x, size %d\n",
VMEM_LOGI("Free virt addr %p, phy addr 0x%lx, size %d\n",
params->vir_address, params->phy_address, params->size);
if (params->vir_address != MAP_FAILED && params->vir_address != NULL)
munmap(params->vir_address, params->size);
@@ -188,7 +187,7 @@ VMEM_destroy(void *vmem)
VmemContext *ctx = (VmemContext *)vmem;
if (ctx->fd_alloc != -1)
close(ctx->fd_alloc);
free(vmem);
}
@@ -215,7 +214,7 @@ VMEM_export(void *vmem, VmemParams *params)
}
params->fd = p.fd;
VMEM_LOGI("Exported phy addr 0x%08x to fd %d, size %d\n",
VMEM_LOGI("Exported phy addr 0x%lx to fd %d, size %d\n",
params->phy_address, params->fd, params->size);
return VMEM_STATUS_OK;
@@ -241,7 +240,7 @@ VMEM_import(void *vmem, VmemParams *params)
params->phy_address = p.bus_address;
params->size = p.size;
VMEM_LOGI("Imported fd %d to phy addr 0x%08x, size %d\n",
VMEM_LOGI("Imported fd %d to phy addr 0x%lx, size %d\n",
params->fd, params->phy_address, params->size);
return VMEM_STATUS_OK;
@@ -256,7 +255,7 @@ VMEM_release(void *vmem, VmemParams *params)
return VMEM_STATUS_ERROR;
ctx = (VmemContext *)vmem;
VMEM_LOGI("Released imported phy addr 0x%08x, fd %d, size %d\n",
VMEM_LOGI("Released imported phy addr 0x%lx, fd %d, size %d\n",
params->phy_address, params->fd, params->size);
if (params->vir_address != MAP_FAILED && params->vir_address != NULL)
munmap(params->vir_address, params->size);
@@ -273,6 +272,49 @@ VMEM_release(void *vmem, VmemParams *params)
return VMEM_STATUS_OK;
}
VmemStatus
VMEM_flush_cache(void *vmem, VmemParams *params,VmemCacheDir dir)
{
VmemContext *ctx = NULL;
VidmemParams p;
int ret;
if (vmem == NULL || params == NULL)
return VMEM_STATUS_ERROR;
ctx = (VmemContext *)vmem;
VMEM_LOGI("Flush phy addr 0x%lx, size %d,dir:%d\n",
params->phy_address, params->size,dir);
if (params->phy_address != 0)
{
memset(&p, 0, sizeof(p));
p.bus_address = params->phy_address;
if(dir == VEME_CACHE_DIR_TO_DEV)
{
ret = ioctl(ctx->fd_alloc, MEMORY_IOC_DMABUF_FLUSH_CACHE, &p);
}else if(dir == VEME_CACHE_DIR_FROM_DEV)
{
ret = ioctl(ctx->fd_alloc, MEMORY_IOC_DMABUF_INVALID_CACHE, &p);
}
else
{
return VMEM_STATUS_ERROR;
}
if(ret)
{
VMEM_LOGE("fail ret %d\n",ret);
return VMEM_STATUS_ERROR;
}
return VMEM_STATUS_OK;
}
return VMEM_STATUS_ERROR;
}
static int getLogLevel()
{
char *env = getenv("VMEM_LOG_LEVEL");

View File

@@ -34,11 +34,16 @@ extern "C" {
#define VMEM_FLAG_CMA 0x00000008
/* Use VI reserved memory */
#define VMEM_FLAG_VI 0x00000010
/* Buffer enable cache */
#define VMEM_FLAG_ENABLE_CACHE 0x00000020
/* Alloc rsvmem pool region id should be 0~15 */
#define MAX_REGION_ID 15
#define SET_ALLOC_FLAG_REGION(flag, region_id) (flag & 0x00ffffff) | (region_id << 24)
#define GET_ALLOC_FLAG_REGION(flag) (flag >> 24)
typedef enum _VmemStatus
{
VMEM_STATUS_OK = 0,
@@ -50,11 +55,17 @@ typedef struct _VmemParams
{
int size;
int flags;
unsigned int phy_address;
unsigned long phy_address;
void *vir_address;
int fd;
} VmemParams;
typedef enum{
VEME_CACHE_DIR_TO_DEV = 0,
VEME_CACHE_DIR_FROM_DEV,
VEME_CACHE_DIR_INVALID,
}VmemCacheDir;
VmemStatus VMEM_create(void **vmem);
VmemStatus VMEM_allocate(void *vmem, VmemParams *params);
VmemStatus VMEM_mmap(void *vmem, VmemParams *params);
@@ -65,6 +76,8 @@ VmemStatus VMEM_export(void *vmem, VmemParams *params);
VmemStatus VMEM_import(void *vmem, VmemParams *params);
VmemStatus VMEM_release(void *vmem, VmemParams *params);
VmemStatus VMEM_flush_cache(void *vmem, VmemParams *params,VmemCacheDir dir);
#ifdef __cplusplus
}
#endif

View File

@@ -120,20 +120,20 @@ int main(int argc, char **argv)
}
if (VMEM_mmap(vmem, params) != VMEM_STATUS_OK)
{
printf("ERROR: Failed to mmap busAddress: 0x%08x\n",
printf("ERROR: Failed to mmap busAddress: 0x%lx\n",
params->phy_address);
err = 1;
break;
}
if (VMEM_export(vmem, params) != VMEM_STATUS_OK)
{
printf("ERROR: Failed to export buffer: 0x%08x\n",
printf("ERROR: Failed to export buffer: 0x%lx\n",
params->phy_address);
err = 1;
break;
}
printf("Allocated buffer %d of type %d at paddr 0x%08x vaddr %p size %d fd %d\n",
printf("Allocated buffer %d of type %d at paddr 0x%lx vaddr %p size %d fd %d\n",
i, type, params->phy_address, params->vir_address, size, params->fd);
memset(&imp_params, 0, sizeof(imp_params));
@@ -145,7 +145,7 @@ int main(int argc, char **argv)
break;
}
printf("Imported fd %d: paddr 0x%08x vaddr %p size %d\n",
printf("Imported fd %d: paddr 0x%lx vaddr %p size %d\n",
params->fd, params->phy_address, params->vir_address, size);
VMEM_release(vmem, &imp_params);
}

View File

@@ -165,7 +165,8 @@ static int sg_table_map(struct device *dev, struct virtio_vdmabuf_buf *exp_buf,
case VIRTIO_VDMABUF_HEAP_TYPE_SYSTEM:
case VIRTIO_VDMABUF_HEAP_TYPE_SYSTEM_CONTIG:
/* SYSTEM, SYSTEM_CONFIG has the same logic */
if (dma_map_sgtable(dev, sgt, dir, 0)) {
if (dma_map_sgtable(dev, sgt, dir, exp_buf->flags &
VIRTIO_VDAMBUF_NONCACHED ? DMA_ATTR_SKIP_CPU_SYNC : 0)) {
dev_err(dev, "[%s:%d] error\n",
__func__, __LINE__);
sg_free_table(sgt);
@@ -204,7 +205,8 @@ static int sg_table_unmap(struct device *dev, struct virtio_vdmabuf_buf *exp_buf
case VIRTIO_VDMABUF_HEAP_TYPE_USER:
case VIRTIO_VDMABUF_HEAP_TYPE_SYSTEM:
case VIRTIO_VDMABUF_HEAP_TYPE_SYSTEM_CONTIG:
dma_unmap_sgtable(dev, sgt, dir, 0);
dma_unmap_sgtable(dev, sgt, dir, exp_buf->flags &
VIRTIO_VDAMBUF_NONCACHED ? DMA_ATTR_SKIP_CPU_SYNC : 0);
break;
case VIRTIO_VDMABUF_HEAP_TYPE_CARVEOUT:

View File

@@ -60,6 +60,7 @@ struct rfkill_wlan_data {
static struct rfkill_wlan_data *g_rfkill = NULL;
static int power_set_time = 0;
static int support_power_ctrl = 0; //Used to control whether power switch control is supported.
static const char wlan_name[] =
#if defined (CONFIG_BCM4330)
@@ -660,6 +661,15 @@ static int wlan_platdata_parse_dt(struct device *dev,
LOG("%s: get property: WIFI,poweren_gpio = %d, flags = %d.\n", __func__, gpio, flags);
} else data->power_n.io = -1;
gpio = of_get_named_gpio_flags(node, "WIFI,vbat_gpio", 0, &flags);
if (of_find_property(node, "support_power_ctrl", NULL)) {
support_power_ctrl = true;
LOG("%s: Turn off the power during suspension and turn it on when resuming, support_power_ctrl = %d.\n", __func__, support_power_ctrl);
} else {
support_power_ctrl = false;
LOG("%s: power is only turned on during initialization and is not controlled afterwards, support_power_ctrl = %d.\n", __func__, support_power_ctrl);
}
if (gpio_is_valid(gpio)) {
data->vbat_n.io = gpio;
data->vbat_n.enable = (flags == GPIO_ACTIVE_HIGH) ? 1:0;
@@ -901,12 +911,53 @@ static int rfkill_wlan_remove(struct platform_device *pdev)
static int rfkill_wlan_suspend(struct platform_device *pdev, pm_message_t state)
{
struct rfkill_wlan_data *mrfkill = g_rfkill;
struct rksdmmc_gpio *poweron, *reset;
poweron = &mrfkill->pdata->power_n;
reset = &mrfkill->pdata->reset_n;
// turn off the wifi's power
if( support_power_ctrl ){
if (gpio_is_valid(poweron->io)) {
gpio_set_value(poweron->io, !(poweron->enable));
msleep(100);
}
if (gpio_is_valid(reset->io)) {
gpio_set_value(reset->io, !(reset->enable));
}
wifi_power_state = 0;
LOG("wifi shut off power.\n");
}
LOG("Enter %s\n", __func__);
return 0;
}
static int rfkill_wlan_resume(struct platform_device *pdev)
{
struct rfkill_wlan_data *mrfkill = g_rfkill;
struct rksdmmc_gpio *poweron, *reset;
poweron = &mrfkill->pdata->power_n;
reset = &mrfkill->pdata->reset_n;
// turn on the wifi's power
if( support_power_ctrl ){
if (gpio_is_valid(poweron->io)) {
gpio_set_value(poweron->io, poweron->enable);
msleep(500);
}
if (gpio_is_valid(reset->io)) {
gpio_set_value(reset->io, reset->enable);
msleep(100);
}
wifi_power_state = 1;
LOG("wifi turn on power. %d\n", poweron->io);
}
LOG("Enter %s\n", __func__);
return 0;
}