Merge commit '8bbe906daa75d355607df9b586a5beb7adf3bf45'

* commit '8bbe906daa75d355607df9b586a5beb7adf3bf45': (31 commits)
  mfd: display-serdes: power off remote serdes while shutdown
  ARM: dts: rockchip: rv1106g-evb2-v12-wakeup add rtt for vicap node
  arm64: dts: rockchip: rk3588s: add winusb reboot mode.
  dt-bindings: soc: rockchip: add reboot mode winusb.
  MALI: bifrost: Fix a null pointer exception when event tracing is enabled
  arm64: dts: rockchip: rk3588-vehicle-evb-v22: Use location name for camera regulators
  media: i2c: maxim4c: Fix unbalanced disable of PoC regulator
  usb: host: ohci-platform: enable async suspend for rk3588
  arm64: dts: rockchip: rk3588s: Add compatible for ohci
  arm64: dts: rockchip: rk3588-linux: set rcu_expedited/rcu_nocbs
  arm64: dts: rockchip: rk3588-android: set rcu_expedited/rcu_nocbs
  arm64: rockchip_linux_defconfig: enable configs needed for RCU perf/power optimizations
  arm64: rockchip_defconfig: enable configs needed for RCU perf/power optimizations
  ARM: dts: rockchip: rv1106g-evb2-v12-wakeup add rtt for isp node
  arm64: dts: rockchip: rk3562-evb1-cam: add dw9714 supply control
  media: rockchip: isp: fix resume hold by lut error
  media: rockchip: isp: suspend resume with rtt
  media: rockchip: isp: pm add call sensor s_power
  arm64: dts: rockchip: update rk3568-evb1-ddr4-v10-dual-lvds relevant files
  ARM: dts: rockchip: add rv1106g-4k dts
  ...

Change-Id: I7cafbe314407a130b7ec94675b83b87d82079468
This commit is contained in:
Tao Huang
2023-10-24 10:17:21 +08:00
52 changed files with 1409 additions and 588 deletions

View File

@@ -1134,6 +1134,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rv1106g-evb1-rgb-display-v11.dtb \
rv1106g-evb1-v10.dtb \
rv1106g-evb1-v11.dtb \
rv1106g-evb1-v11-4k.dtb \
rv1106g-evb1-v11-cvr.dtb \
rv1106g-evb1-v11-cvr-dual-cam.dtb \
rv1106g-evb1-v11-spi-nand-cvr.dtb \

View File

@@ -53,7 +53,7 @@
csi_dphy_input6: endpoint@6 {
reg = <6>;
remote-endpoint = <&imx415_out>;
data-lanes = <1 2 3 4>;
data-lanes = <1 2>;
};
};
@@ -225,7 +225,7 @@
port {
imx415_out: endpoint {
remote-endpoint = <&csi_dphy_input6>;
data-lanes = <1 2 3 4>;
data-lanes = <1 2>;
};
};
};

View File

@@ -0,0 +1,17 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include "rv1106g-evb1-v11.dts"
/ {
model = "Rockchip RV1106G EVB1 V11 Board For RV1106G3 4K Unite";
compatible = "rockchip,rv1106g-evb1-v11-4k", "rockchip,rv1106";
};
&rkisp {
rockchip,unite-en;
};

View File

@@ -223,7 +223,8 @@
&rkcif_mipi_lvds {
status = "okay";
//memory-region-thunderboot = <&rkisp_thunderboot>;
memory-region-thunderboot = <&rkisp_thunderboot>;
rtt-suspend;
pinctrl-names = "default";
pinctrl-0 = <&mipi_pins>;
@@ -253,6 +254,9 @@
&rkisp_vir0 {
status = "okay";
memory-region-thunderboot = <&rkisp_thunderboot>;
rtt-suspend;
port@0 {
isp_in: endpoint {
remote-endpoint = <&mipi_lvds_sditf>;

View File

@@ -37,6 +37,7 @@ CONFIG_SPI=y
CONFIG_USB_SUPPORT=y
CONFIG_VFAT_FS=y
CONFIG_VIDEO_GC2053=m
CONFIG_VIDEO_IMX415=m
CONFIG_VIDEO_OS04A10=m
CONFIG_VIDEO_SC3336=m
CONFIG_VIDEO_SC4336=m

View File

@@ -59,6 +59,7 @@ static struct rv1106_sleep_ddr_data ddr_data;
static void __iomem *pmucru_base;
static void __iomem *cru_base;
static void __iomem *pvtpllcru_base;
static void __iomem *pericru_base;
static void __iomem *vicru_base;
static void __iomem *npucru_base;
@@ -105,6 +106,10 @@ static struct reg_region vd_core_reg_rgns[] = {
{ REG_REGION(0x300, 0x310, 4, &corecru_base, WMSK_VAL)},
{ REG_REGION(0x800, 0x804, 4, &corecru_base, WMSK_VAL)},
/* pvtpll_cru */
{ REG_REGION(0x00, 0x24, 4, &pvtpllcru_base, WMSK_VAL)},
{ REG_REGION(0x30, 0x54, 4, &pvtpllcru_base, WMSK_VAL)},
/* core_sgrf */
{ REG_REGION(0x004, 0x014, 4, &coresgrf_base, 0)},
{ REG_REGION(0x000, 0x000, 4, &coresgrf_base, 0)},
@@ -1165,6 +1170,7 @@ static int __init rv1106_suspend_init(struct device_node *np)
pmucru_base = dev_reg_base + RV1106_PMUCRU_OFFSET;
cru_base = dev_reg_base + RV1106_CRU_OFFSET;
pvtpllcru_base = dev_reg_base + RV1106_PVTPLLCRU_OFFSET;
pericru_base = dev_reg_base + RV1106_PERICRU_OFFSET;
vicru_base = dev_reg_base + RV1106_VICRU_OFFSET;
npucru_base = dev_reg_base + RV1106_NPUCRU_OFFSET;

View File

@@ -35,6 +35,7 @@
#define RV1106_PMUCRU_OFFSET 0x3a0000
#define RV1106_CRU_OFFSET 0x3b0000
#define RV1106_PVTPLLCRU_OFFSET 0x3b1000
#define RV1106_PERICRU_OFFSET 0x3b2000
#define RV1106_VICRU_OFFSET 0x3b4000
#define RV1106_NPUCRU_OFFSET 0x3b6000

View File

@@ -155,6 +155,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3567-evb2-lp4x-v10-dual-lvds.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-dual-camera.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-dual-lvds.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-dual-lvds-linux.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-linux.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-linux-amp.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-linux-spi-nor.dtb

View File

@@ -59,6 +59,7 @@
compatible = "dongwoon,dw9714";
status = "okay";
reg = <0x0c>;
avdd-supply = <&vcc2v8_dvp>;
rockchip,vcm-start-current = <10>;
rockchip,vcm-rated-current = <85>;
rockchip,vcm-step-mode = <5>;

View File

@@ -0,0 +1,23 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
/dts-v1/;
#include <dt-bindings/display/rockchip_vop.h>
#include "rk3568-evb1-ddr4-v10-dual-lvds.dtsi"
#include "rk3568-linux.dtsi"
/ {
model = "Rockchip RK3568 EVB1 V10 Board with Dual LVDS";
compatible = "rockchip,rk3568-evb1-ddr4-v10-dual-lvds", "rockchip,rk3568";
};
&vp0 {
cursor-win-id = <ROCKCHIP_VOP2_CLUSTER0>;
};
&vp1 {
cursor-win-id = <ROCKCHIP_VOP2_CLUSTER1>;
};

View File

@@ -5,165 +5,10 @@
/dts-v1/;
#include <dt-bindings/display/media-bus-format.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include "rk3568-evb1-ddr4-v10.dtsi"
#include "rk3568-evb1-ddr4-v10-dual-lvds.dtsi"
#include "rk3568-android.dtsi"
/ {
panel {
compatible = "simple-panel";
backlight = <&backlight>;
power-supply = <&vcc3v3_lcd0_n>;
enable-delay-ms = <20>;
prepare-delay-ms = <20>;
unprepare-delay-ms = <20>;
disable-delay-ms = <20>;
bus-format = <MEDIA_BUS_FMT_RGB666_1X7X3_SPWG>;
width-mm = <217>;
height-mm = <136>;
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <134000000>;
hactive = <1600>;
vactive = <1280>;
hback-porch = <60>;
hfront-porch = <60>;
vback-porch = <4>;
vfront-porch = <2>;
hsync-len = <8>;
vsync-len = <2>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
/**
* Panel <----> LVDS0
* Panel <----> LVDS1
*/
port@0 {
reg = <0>;
dual-lvds-left-pixels;
panel_in_lvds0: endpoint {
remote-endpoint = <&lvds0_out_panel>;
};
};
port@1 {
reg = <1>;
dual-lvds-right-pixels;
panel_in_lvds1: endpoint {
remote-endpoint = <&lvds1_out_panel>;
};
};
};
};
};
&backlight1 {
status = "okay";
};
&backlight {
status = "okay";
};
&lvds {
status = "okay";
dual-channel;
ports {
port@1 {
reg = <1>;
lvds0_out_panel: endpoint {
remote-endpoint = <&panel_in_lvds0>;
};
};
};
};
&lvds1 {
status = "okay";
ports {
port@1 {
reg = <1>;
lvds1_out_panel: endpoint {
remote-endpoint = <&panel_in_lvds1>;
};
};
};
};
&lvds_in_vp1 {
status = "okay";
};
&lvds1_in_vp1 {
status = "disabled";
};
&lvds1_in_vp2 {
status = "okay";
};
/* enable hdmi */
&hdmi_in_vp1 {
status = "okay";
};
/* enable video phy */
&video_phy0 {
status = "okay";
};
&video_phy1 {
status = "okay";
};
/* disable other encoder output */
&dsi0 {
status = "disabled";
};
&dsi0_in_vp0 {
status = "disabled";
};
&dsi0_in_vp1 {
status = "disabled";
};
&dsi1_in_vp1 {
status = "disabled";
};
&edp_in_vp1 {
status = "disabled";
};
&rgb_in_vp2 {
status = "disabled";
};
&vcc3v3_lcd0_n {
gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
&vcc3v3_lcd1_n {
gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>;
enable-active-high;
model = "Rockchip RK3568 EVB1 V10 Board with Dual LVDS";
compatible = "rockchip,rk3568-evb1-ddr4-v10-dual-lvds", "rockchip,rk3568";
};

View File

@@ -0,0 +1,161 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*/
#include <dt-bindings/display/media-bus-format.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include "rk3568-evb1-ddr4-v10.dtsi"
/ {
panel {
compatible = "simple-panel";
backlight = <&backlight>;
power-supply = <&vcc3v3_lcd0_n>;
enable-delay-ms = <20>;
prepare-delay-ms = <20>;
unprepare-delay-ms = <20>;
disable-delay-ms = <20>;
bus-format = <MEDIA_BUS_FMT_RGB666_1X7X3_SPWG>;
width-mm = <217>;
height-mm = <136>;
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <134000000>;
hactive = <1600>;
vactive = <1280>;
hback-porch = <60>;
hfront-porch = <60>;
vback-porch = <4>;
vfront-porch = <2>;
hsync-len = <8>;
vsync-len = <2>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
ports {
#address-cells = <1>;
#size-cells = <0>;
/**
* Panel <----> LVDS0
* Panel <----> LVDS1
*/
port@0 {
reg = <0>;
dual-lvds-left-pixels;
panel_in_lvds0: endpoint {
remote-endpoint = <&lvds0_out_panel>;
};
};
port@1 {
reg = <1>;
dual-lvds-right-pixels;
panel_in_lvds1: endpoint {
remote-endpoint = <&lvds1_out_panel>;
};
};
};
};
};
&backlight1 {
status = "okay";
};
&backlight {
status = "okay";
};
&dsi0 {
status = "disabled";
};
&dsi0_in_vp0 {
status = "disabled";
};
&dsi0_in_vp1 {
status = "disabled";
};
&dsi1_in_vp1 {
status = "disabled";
};
&edp_in_vp1 {
status = "disabled";
};
&hdmi_in_vp1 {
status = "okay";
};
&lvds {
status = "okay";
dual-channel;
ports {
port@1 {
reg = <1>;
lvds0_out_panel: endpoint {
remote-endpoint = <&panel_in_lvds0>;
};
};
};
};
&lvds1 {
status = "okay";
ports {
port@1 {
reg = <1>;
lvds1_out_panel: endpoint {
remote-endpoint = <&panel_in_lvds1>;
};
};
};
};
&lvds_in_vp1 {
status = "okay";
};
&lvds1_in_vp1 {
status = "disabled";
};
&lvds1_in_vp2 {
status = "okay";
};
&rgb_in_vp2 {
status = "disabled";
};
&video_phy0 {
status = "okay";
};
&video_phy1 {
status = "okay";
};
&vcc3v3_lcd0_n {
gpio = <&gpio0 RK_PC7 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
&vcc3v3_lcd1_n {
gpio = <&gpio0 RK_PC5 GPIO_ACTIVE_HIGH>;
enable-active-high;
};

View File

@@ -6,7 +6,7 @@
/ {
chosen: chosen {
bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0";
bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 rcupdate.rcu_expedited=1 rcu_nocbs=all";
};
cspmu: cspmu@fd10c000 {

View File

@@ -12,7 +12,7 @@
};
chosen: chosen {
bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=PARTUUID=614e0000-0000 rw rootwait";
bootargs = "earlycon=uart8250,mmio32,0xfeb50000 console=ttyFIQ0 irqchip.gicv3_pseudo_nmi=0 root=PARTUUID=614e0000-0000 rw rootwait rcupdate.rcu_expedited=1 rcu_nocbs=all";
};
cspmu: cspmu@fd10c000 {

View File

@@ -149,11 +149,10 @@
};
};
camera1_vcc12v_buck: camera1_vcc12v-buck {
dcphy0_vcc12v_buck: dcphy0_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "camera1_vcc12v_buck";
regulator-name = "dcphy0_vcc12v_buck";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
@@ -167,11 +166,10 @@
};
};
camera2_vcc12v_buck: camera2_vcc12v-buck {
dcphy1_vcc12v_buck: dcphy1_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "camera2_vcc12v_buck";
regulator-name = "dcphy1_vcc12v_buck";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
@@ -185,11 +183,10 @@
};
};
camera3_vcc12v_buck: camera3_vcc12v-buck {
dphy0_vcc12v_buck: dphy0_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "camera3_vcc12v_buck";
regulator-name = "dphy0_vcc12v_buck";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
@@ -203,11 +200,10 @@
};
};
camera4_vcc12v_buck: camera4_vcc12v-buck {
dphy3_vcc12v_buck: dphy3_vcc12v-buck {
compatible = "regulator-fixed";
regulator-name = "camera4_vcc12v_buck";
regulator-name = "dphy3_vcc12v_buck";
regulator-boot-on;
regulator-always-on;
regulator-min-microvolt = <12000000>;
regulator-max-microvolt = <12000000>;
enable-active-high;
@@ -348,7 +344,7 @@
};
&max96712_dphy3_poc {
vin-supply = <&camera1_vcc12v_buck>;
vin-supply = <&dphy3_vcc12v_buck>;
};
&avdd1v8_ddr_pll_s0 {
@@ -373,12 +369,12 @@
};
&i2c2_bu18tl82 {
//route-enable;
use-delay-work;
route-enable;
//use-delay-work;
};
&i2c2_bu18rl82 {
use-delay-work;
//use-delay-work;
vpower-supply = <&lcd1_vcc12v_buck>;
};
@@ -389,11 +385,11 @@
};
&i2c4_bu18tl82 {
use-delay-work;
//use-delay-work;
};
&i2c4_bu18rl82 {
use-delay-work;
//use-delay-work;
vpower-supply = <&lcd5_vcc12v_buck>;
};
@@ -435,11 +431,11 @@
};
&i2c5_bu18tl82 {
use-delay-work;
//use-delay-work;
};
&i2c5_bu18rl82 {
use-delay-work;
//use-delay-work;
vpower-supply = <&lcd3_vcc12v_buck>;
};
@@ -450,8 +446,8 @@
};
&i2c6_bu18tl82 {
//route-enable;
use-delay-work;
route-enable;
//use-delay-work;
};
&i2c6_bu18rl82 {
@@ -565,11 +561,11 @@
};
&route_dsi0 {
status = "disabled";
status = "okay";
};
&route_dsi1 {
status = "disabled";
status = "okay";
};
&u2phy1_otg {

View File

@@ -2651,7 +2651,7 @@
};
usb_host0_ohci: usb@fc840000 {
compatible = "generic-ohci";
compatible = "rockchip,rk3588-ohci", "generic-ohci";
reg = <0x0 0xfc840000 0x0 0x40000>;
interrupts = <GIC_SPI 216 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST_ARB0>, <&u2phy2>, <&aclk_usb>;
@@ -2676,7 +2676,7 @@
};
usb_host1_ohci: usb@fc8c0000 {
compatible = "generic-ohci";
compatible = "rockchip,rk3588-ohci", "generic-ohci";
reg = <0x0 0xfc8c0000 0x0 0x40000>;
interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST_ARB1>, <&u2phy3>, <&aclk_usb>;
@@ -2760,6 +2760,8 @@
mode-panic = <BOOT_PANIC>;
mode-watchdog = <BOOT_WATCHDOG>;
mode-quiescent = <BOOT_QUIESCENT>;
/* add a mode to capture the ramdump through usb */
mode-winusb = <BOOT_WINUSB>;
};
};

View File

@@ -9,6 +9,10 @@ CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
CONFIG_PSI=y
CONFIG_RCU_EXPERT=y
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_RCU_BOOST=y
CONFIG_RCU_NOCB_CPU=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_IKHEADERS=m

View File

@@ -4,6 +4,9 @@ CONFIG_SYSVIPC=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_RCU_EXPERT=y
CONFIG_RCU_FAST_NO_HZ=y
CONFIG_RCU_NOCB_CPU=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=18

View File

@@ -1604,6 +1604,10 @@ static int kbasep_kcpu_fence_signal_init(struct kbase_kcpu_command_queue *kcpu_q
if (!kcpu_fence)
return -ENOMEM;
/* Set reference to KCPU metadata and increment refcount */
kcpu_fence->metadata = kcpu_queue->metadata;
WARN_ON(!kbase_refcount_inc_not_zero(&kcpu_fence->metadata->refcount));
#if (KERNEL_VERSION(4, 10, 0) > LINUX_VERSION_CODE)
fence_out = (struct fence *)kcpu_fence;
#else
@@ -1625,10 +1629,6 @@ static int kbasep_kcpu_fence_signal_init(struct kbase_kcpu_command_queue *kcpu_q
dma_fence_get(fence_out);
#endif
/* Set reference to KCPU metadata and increment refcount */
kcpu_fence->metadata = kcpu_queue->metadata;
WARN_ON(!kbase_refcount_inc_not_zero(&kcpu_fence->metadata->refcount));
/* create a sync_file fd representing the fence */
*sync_file = sync_file_create(fence_out);
if (!(*sync_file)) {

View File

@@ -29,10 +29,12 @@
* V2.03.00
* 1. remote device add the maxim4c prefix to driver name.
*
* V2.04.02
* V2.04.03
* 1. Add regulator supplier dependencies.
* 2. Add config ssc-ratio property
* 3. Add debugfs entry to change MIPI timing
* 4. Use PM runtime autosuspend feature
* 5. Fix unbalanced disabling for PoC regulator
*
*/
#include <linux/clk.h>
@@ -63,7 +65,7 @@
#include "maxim4c_api.h"
#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x02)
#define DRIVER_VERSION KERNEL_VERSION(2, 0x04, 0x03)
#define MAXIM4C_XVCLK_FREQ 25000000
@@ -681,6 +683,14 @@ static int maxim4c_probe(struct i2c_client *client,
if (ret)
goto err_destroy_mutex;
ret = maxim4c_remote_device_power_on(maxim4c);
if (ret)
dev_warn(dev, "Power on PoC regulator failed\n");
pm_runtime_set_active(dev);
pm_runtime_get_noresume(dev);
pm_runtime_enable(dev);
ret = maxim4c_check_local_chipid(maxim4c);
if (ret)
goto err_power_off;
@@ -704,9 +714,10 @@ static int maxim4c_probe(struct i2c_client *client,
goto err_power_off;
#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_idle(dev);
pm_runtime_set_autosuspend_delay(dev, 1000);
pm_runtime_use_autosuspend(dev);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
#endif /* MAXIM4C_TEST_PATTERN */
@@ -731,9 +742,10 @@ static int maxim4c_probe(struct i2c_client *client,
maxim4c_lock_irq_init(maxim4c);
maxim4c_lock_state_work_init(maxim4c);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_idle(dev);
pm_runtime_set_autosuspend_delay(dev, 1000);
pm_runtime_use_autosuspend(dev);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
@@ -742,6 +754,9 @@ err_dbgfs_deinit:
err_subdev_deinit:
maxim4c_v4l2_subdev_deinit(maxim4c);
err_power_off:
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
maxim4c_remote_device_power_off(maxim4c);
maxim4c_local_device_power_off(maxim4c);
err_destroy_mutex:
mutex_destroy(&maxim4c->mutex);

View File

@@ -589,21 +589,20 @@ static int maxim4c_s_stream(struct v4l2_subdev *sd, int on)
goto unlock_and_return;
if (on) {
ret = pm_runtime_get_sync(&client->dev);
if (ret < 0) {
pm_runtime_put_noidle(&client->dev);
ret = pm_runtime_resume_and_get(&client->dev);
if (ret < 0)
goto unlock_and_return;
}
ret = __maxim4c_start_stream(maxim4c);
if (ret) {
v4l2_err(sd, "start stream failed while write regs\n");
pm_runtime_put(&client->dev);
pm_runtime_put_sync(&client->dev);
goto unlock_and_return;
}
} else {
__maxim4c_stop_stream(maxim4c);
pm_runtime_put(&client->dev);
pm_runtime_mark_last_busy(&client->dev);
pm_runtime_put_autosuspend(&client->dev);
}
maxim4c->streaming = on;

View File

@@ -2046,11 +2046,11 @@ static int sc200ai_probe(struct i2c_client *client,
return -EINVAL;
}
sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_ASIS);
sc200ai->reset_gpio = devm_gpiod_get(dev, "reset", sc200ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW);
if (IS_ERR(sc200ai->reset_gpio))
dev_warn(dev, "Failed to get reset-gpios\n");
sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", GPIOD_ASIS);
sc200ai->pwdn_gpio = devm_gpiod_get(dev, "pwdn", sc200ai->is_thunderboot ? GPIOD_ASIS : GPIOD_OUT_LOW);
if (IS_ERR(sc200ai->pwdn_gpio))
dev_warn(dev, "Failed to get pwdn-gpios\n");

View File

@@ -7,7 +7,7 @@
* V0.0X01.0X01 first version
*/
//#define DEBUG
// #define DEBUG
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/delay.h>
@@ -192,10 +192,10 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = {
{0x3301, 0x09},
{0x3302, 0xff},
{0x3303, 0x10},
{0x3306, 0x60},
{0x3306, 0x68},
{0x3307, 0x02},
{0x330a, 0x01},
{0x330b, 0x10},
{0x330b, 0x18},
{0x330c, 0x16},
{0x330d, 0xff},
{0x3318, 0x02},
@@ -219,8 +219,8 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = {
{0x33b1, 0x80},
{0x33b2, 0x68},
{0x33b3, 0x42},
{0x33f9, 0x70},
{0x33fb, 0xd0},
{0x33f9, 0x78},
{0x33fb, 0xe0},
{0x33fc, 0x0f},
{0x33fd, 0x1f},
{0x349f, 0x03},
@@ -229,9 +229,9 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = {
{0x34a8, 0x42},
{0x34a9, 0x06},
{0x34aa, 0x01},
{0x34ab, 0x23},
{0x34ab, 0x28},
{0x34ac, 0x01},
{0x34ad, 0x84},
{0x34ad, 0x90},
{0x3630, 0xf4},
{0x3633, 0x22},
{0x3639, 0xf4},
@@ -242,9 +242,9 @@ static const struct regval sc2336_linear_10_1920x1080_30fps_regs[] = {
{0x3676, 0xed},
{0x367c, 0x09},
{0x367d, 0x0f},
{0x3690, 0x33},
{0x3691, 0x33},
{0x3692, 0x43},
{0x3690, 0x22},
{0x3691, 0x22},
{0x3692, 0x22},
{0x3698, 0x89},
{0x3699, 0x96},
{0x369a, 0xd0},
@@ -452,15 +452,15 @@ static int sc2336_set_gain_reg(struct sc2336 *sc2336, u32 gain)
coarse_dgain = 0x00;
fine_dgain = gain_factor * 128 / 1000;
} else if (gain_factor < 1000 * 4) { /*2x ~ 4x gain*/
coarse_again = 0x01;
coarse_again = 0x08;
coarse_dgain = 0x00;
fine_dgain = gain_factor * 128 / 1000 / 2;
} else if (gain_factor < 1000 * 8) { /*4x ~ 8x gain*/
coarse_again = 0x03;
coarse_again = 0x09;
coarse_dgain = 0x00;
fine_dgain = gain_factor * 128 / 1000 / 4;
} else if (gain_factor < 1000 * 16) { /*8x ~ 16x gain*/
coarse_again = 0x07;
coarse_again = 0x0b;
coarse_dgain = 0x00;
fine_dgain = gain_factor * 128 / 1000 / 8;
} else if (gain_factor < 1000 * 32) { /*16x ~ 32x gain*/
@@ -481,6 +481,7 @@ static int sc2336_set_gain_reg(struct sc2336 *sc2336, u32 gain)
coarse_dgain = 0x03;
fine_dgain = 0x80;
}
fine_dgain = fine_dgain / 4 * 4;
dev_dbg(&sc2336->client->dev,
"total_gain: 0x%x, d_gain: 0x%x, d_fine_gain: 0x%x, c_gain: 0x%x\n",
gain, coarse_dgain, fine_dgain, coarse_again);
@@ -1148,7 +1149,7 @@ static int sc2336_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_VBLANK:
/* Update max exposure while meeting expected vblanking */
max = sc2336->cur_mode->height + ctrl->val - 8;
max = sc2336->cur_mode->height + ctrl->val - 6;
__v4l2_ctrl_modify_range(sc2336->exposure,
sc2336->exposure->minimum, max,
sc2336->exposure->step,
@@ -1271,7 +1272,7 @@ static int sc2336_initialize_controls(struct sc2336 *sc2336)
V4L2_CID_VBLANK, vblank_def,
SC2336_VTS_MAX - mode->height,
1, vblank_def);
exposure_max = mode->vts_def - 8;
exposure_max = mode->vts_def - 6;
sc2336->exposure = v4l2_ctrl_new_std(handler, &sc2336_ctrl_ops,
V4L2_CID_EXPOSURE, SC2336_EXPOSURE_MIN,
exposure_max, SC2336_EXPOSURE_STEP,

View File

@@ -1225,6 +1225,15 @@ static int mi_frame_end(struct rkisp_stream *stream, u32 state)
struct vb2_buffer *vb2_buf = &stream->curr_buf->vb.vb2_buf;
u64 ns = 0;
if (stream->skip_frame) {
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
list_add_tail(&stream->curr_buf->queue, &stream->buf_queue);
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
if (stream->skip_frame)
stream->skip_frame--;
goto end;
}
/* Dequeue a filled buffer */
for (i = 0; i < isp_fmt->mplanes; i++) {
u32 payload_size =
@@ -1287,6 +1296,7 @@ static int mi_frame_end(struct rkisp_stream *stream, u32 state)
stream->curr_buf = NULL;
}
end:
if (!interlaced ||
(stream->curr_buf == stream->next_buf &&
stream->u.sp.field == RKISP_FIELD_ODD)) {
@@ -1505,7 +1515,7 @@ static int rkisp_start(struct rkisp_stream *stream)
if (stream->id == RKISP_STREAM_MP || stream->id == RKISP_STREAM_SP)
hdr_config_dmatx(dev);
stream->streaming = true;
stream->skip_frame = 0;
return 0;
}

View File

@@ -977,6 +977,15 @@ static int mi_frame_end(struct rkisp_stream *stream, u32 state)
struct vb2_buffer *vb2_buf = &buf->vb.vb2_buf;
u64 ns = 0;
if (stream->skip_frame) {
spin_lock_irqsave(&stream->vbq_lock, lock_flags);
list_add_tail(&buf->queue, &stream->buf_queue);
spin_unlock_irqrestore(&stream->vbq_lock, lock_flags);
if (stream->skip_frame)
stream->skip_frame--;
goto end;
}
/* Dequeue a filled buffer */
for (i = 0; i < isp_fmt->mplanes; i++) {
u32 payload_size = stream->out_fmt.plane_fmt[i].sizeimage;
@@ -1097,7 +1106,7 @@ static int rkisp_start(struct rkisp_stream *stream)
stream->ops->enable_mi(stream);
stream->streaming = true;
stream->skip_frame = 0;
return 0;
}

View File

@@ -15,7 +15,7 @@
#include "isp_external.h"
#include "regs.h"
static void get_remote_mipi_sensor(struct rkisp_device *dev,
void rkisp_get_remote_mipi_sensor(struct rkisp_device *dev,
struct v4l2_subdev **sensor_sd, u32 function)
{
struct media_graph graph;
@@ -191,7 +191,7 @@ static int csi_config(struct rkisp_csi_device *csi)
emd_vc = 0xFF;
emd_dt = 0;
dev->hdr.sensor = NULL;
get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR);
rkisp_get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR);
if (mipi_sensor) {
ctrl = v4l2_ctrl_find(mipi_sensor->ctrl_handler,
CIFISP_CID_EMB_VC);
@@ -527,7 +527,7 @@ int rkisp_csi_get_hdr_cfg(struct rkisp_device *dev, void *arg)
}
return 0;
}
get_remote_mipi_sensor(dev, &sd, type);
rkisp_get_remote_mipi_sensor(dev, &sd, type);
if (!sd) {
v4l2_err(&dev->v4l2_dev, "%s don't find subdev\n", __func__);
return -EINVAL;
@@ -558,7 +558,7 @@ int rkisp_csi_config_patch(struct rkisp_device *dev)
memset(&mode, 0, sizeof(mode));
mode.name = dev->name;
get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_PROC_VIDEO_COMPOSER);
rkisp_get_remote_mipi_sensor(dev, &mipi_sensor, MEDIA_ENT_F_PROC_VIDEO_COMPOSER);
if (!mipi_sensor)
return -EINVAL;
dev->hdr.op_mode = HDR_NORMAL;

View File

@@ -80,4 +80,6 @@ void rkisp_unregister_csi_subdev(struct rkisp_device *dev);
int rkisp_csi_get_hdr_cfg(struct rkisp_device *dev, void *arg);
int rkisp_csi_config_patch(struct rkisp_device *dev);
void rkisp_csi_sof(struct rkisp_device *dev, u8 id);
void rkisp_get_remote_mipi_sensor(struct rkisp_device *dev,
struct v4l2_subdev **sensor_sd, u32 function);
#endif

View File

@@ -52,6 +52,7 @@
#include "regs.h"
#include "rkisp.h"
#include "version.h"
#include "csi.h"
#define RKISP_VERNO_LEN 10
@@ -813,6 +814,15 @@ static int rkisp_get_reserved_mem(struct rkisp_device *isp_dev)
DMA_BIDIRECTIONAL);
ret = dma_mapping_error(dev, isp_dev->resmem_addr);
isp_dev->is_thunderboot = true;
isp_dev->is_rtt_suspend = false;
isp_dev->is_rtt_first = true;
if (device_property_read_bool(dev, "rtt-suspend")) {
isp_dev->is_rtt_suspend = true;
if (!isp_dev->hw_dev->is_thunderboot) {
isp_dev->is_thunderboot = false;
isp_dev->is_rtt_first = false;
}
}
dev_info(dev, "Allocated reserved memory, paddr: 0x%x\n", (u32)isp_dev->resmem_pa);
return ret;
}
@@ -1004,9 +1014,159 @@ static int __init rkisp_clr_unready_dev(void)
late_initcall_sync(rkisp_clr_unready_dev);
#endif
static int rkisp_pm_prepare(struct device *dev)
{
struct rkisp_device *isp_dev = dev_get_drvdata(dev);
struct rkisp_hw_dev *hw = isp_dev->hw_dev;
struct rkisp_pipeline *p = &isp_dev->pipe;
unsigned long lock_flags = 0;
int i, on = 0, time = 100;
if (isp_dev->isp_state & ISP_STOP) {
if (pm_runtime_active(dev) &&
rkisp_link_sensor(isp_dev->isp_inp)) {
struct v4l2_subdev *mipi_sensor = NULL;
rkisp_get_remote_mipi_sensor(isp_dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR);
if (mipi_sensor)
v4l2_subdev_call(mipi_sensor, core, s_power, 0);
}
return 0;
}
isp_dev->suspend_sync = false;
isp_dev->is_suspend = true;
if (rkisp_link_sensor(isp_dev->isp_inp)) {
for (i = p->num_subdevs - 1; i >= 0; i--)
v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
} else if (isp_dev->isp_inp & INP_CIF && !(IS_HDR_RDBK(isp_dev->rd_mode))) {
v4l2_subdev_call(p->subdevs[0], core, ioctl, RKISP_VICAP_CMD_QUICK_STREAM, &on);
}
if (IS_HDR_RDBK(isp_dev->rd_mode)) {
spin_lock_irqsave(&hw->rdbk_lock, lock_flags);
if (!hw->is_idle && hw->cur_dev_id == isp_dev->dev_id)
isp_dev->suspend_sync = true;
spin_unlock_irqrestore(&hw->rdbk_lock, lock_flags);
} else {
/* wait one frame for online */
isp_dev->suspend_sync = true;
if (hw->isp_size[isp_dev->dev_id].fps)
time = 1000 / hw->isp_size[isp_dev->dev_id].fps;
}
if (isp_dev->suspend_sync) {
wait_for_completion_timeout(&isp_dev->pm_cmpl, msecs_to_jiffies(time));
isp_dev->suspend_sync = false;
}
if (rkisp_link_sensor(isp_dev->isp_inp)) {
for (i = p->num_subdevs - 1; i >= 0; i--)
v4l2_subdev_call(p->subdevs[i], core, s_power, 0);
}
return 0;
}
static void rkisp_pm_complete(struct device *dev)
{
struct rkisp_device *isp_dev = dev_get_drvdata(dev);
struct rkisp_hw_dev *hw = isp_dev->hw_dev;
struct rkisp_pipeline *p = &isp_dev->pipe;
struct rkisp_stream *stream;
int i, on = 1, rd_mode = isp_dev->rd_mode;
if (isp_dev->isp_state & ISP_STOP) {
if (pm_runtime_active(dev) &&
rkisp_link_sensor(isp_dev->isp_inp)) {
struct v4l2_subdev *mipi_sensor = NULL;
rkisp_get_remote_mipi_sensor(isp_dev, &mipi_sensor, MEDIA_ENT_F_CAM_SENSOR);
if (mipi_sensor)
v4l2_subdev_call(mipi_sensor, core, s_power, 1);
}
return;
}
if (isp_dev->is_rtt_suspend) {
rkisp_save_tb_info(isp_dev);
v4l2_info(&isp_dev->v4l2_dev,
"tb info en:%d comp:%d cnt:%d w:%d h:%d cam:%d idx:%d mode:%d\n",
isp_dev->tb_head.enable, isp_dev->tb_head.complete,
isp_dev->tb_head.frm_total, isp_dev->tb_head.width,
isp_dev->tb_head.height, isp_dev->tb_head.camera_num,
isp_dev->tb_head.camera_index, isp_dev->tb_head.rtt_mode);
isp_dev->is_first_double = false;
switch (isp_dev->tb_head.rtt_mode) {
case RKISP_RTT_MODE_ONE_FRAME:
isp_dev->is_first_double = true;
/* switch to readback mode */
switch (rd_mode) {
case HDR_LINEX3_DDR:
isp_dev->rd_mode = HDR_RDBK_FRAME3;
break;
case HDR_LINEX2_DDR:
isp_dev->rd_mode = HDR_RDBK_FRAME2;
break;
default:
isp_dev->rd_mode = HDR_RDBK_FRAME1;
}
break;
case RKISP_RTT_MODE_MULTI_FRAME:
default:
if (isp_dev->tb_head.rtt_mode != RKISP_RTT_MODE_MULTI_FRAME)
v4l2_warn(&isp_dev->v4l2_dev,
"invalid rtt mode:%d, change to mode:%d\n",
isp_dev->tb_head.rtt_mode, RKISP_RTT_MODE_MULTI_FRAME);
if (!hw->is_single)
break;
/* switch to online mode for single sensor */
switch (rd_mode) {
case HDR_RDBK_FRAME3:
isp_dev->rd_mode = HDR_LINEX3_DDR;
break;
case HDR_RDBK_FRAME2:
isp_dev->rd_mode = HDR_LINEX2_DDR;
break;
default:
isp_dev->rd_mode = HDR_NORMAL;
}
}
isp_dev->hdr.op_mode = isp_dev->rd_mode;
if (rd_mode != isp_dev->rd_mode && hw->cur_dev_id == isp_dev->dev_id) {
rkisp_unite_write(isp_dev, CSI2RX_CTRL0,
SW_IBUF_OP_MODE(isp_dev->rd_mode), true);
if (IS_HDR_RDBK(isp_dev->rd_mode))
rkisp_unite_set_bits(isp_dev, CTRL_SWS_CFG, 0,
SW_MPIP_DROP_FRM_DIS, true);
else
rkisp_unite_clear_bits(isp_dev, CTRL_SWS_CFG,
SW_MPIP_DROP_FRM_DIS, true);
}
}
isp_dev->is_suspend = false;
isp_dev->isp_state = ISP_START | ISP_FRAME_END;
for (i = 0; i < RKISP_MAX_STREAM; i++) {
stream = &isp_dev->cap_dev.stream[i];
if (i == RKISP_STREAM_VIR || !stream->streaming)
continue;
stream->skip_frame = 1;
}
if (hw->cur_dev_id == isp_dev->dev_id)
rkisp_rdbk_trigger_event(isp_dev, T_CMD_QUEUE, NULL);
if (rkisp_link_sensor(isp_dev->isp_inp)) {
for (i = 0; i < p->num_subdevs; i++)
v4l2_subdev_call(p->subdevs[i], core, s_power, 1);
for (i = 0; i < p->num_subdevs; i++)
v4l2_subdev_call(p->subdevs[i], video, s_stream, on);
} else if (isp_dev->isp_inp & INP_CIF && !(IS_HDR_RDBK(isp_dev->rd_mode))) {
v4l2_subdev_call(p->subdevs[0], core, ioctl, RKISP_VICAP_CMD_QUICK_STREAM, &on);
}
}
static const struct dev_pm_ops rkisp_plat_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
.prepare = rkisp_pm_prepare,
.complete = rkisp_pm_complete,
SET_RUNTIME_PM_OPS(rkisp_runtime_suspend, rkisp_runtime_resume, NULL)
};

View File

@@ -235,6 +235,10 @@ struct rkisp_device {
size_t resmem_size;
struct rkisp_thunderboot_resmem_head tb_head;
bool is_thunderboot;
/* first frame for rtt */
bool is_rtt_first;
/* suspend/resume with rtt */
bool is_rtt_suspend;
struct rkisp_tb_stream_info tb_stream_info;
unsigned int tb_addr_idx;
@@ -246,6 +250,8 @@ struct rkisp_device {
struct rkisp_ispp_buf *cur_fbcgain;
struct rkisp_buffer *cur_spbuf;
struct completion pm_cmpl;
struct work_struct rdbk_work;
struct kfifo rdbk_kfifo;
spinlock_t rdbk_lock;
@@ -269,6 +275,8 @@ struct rkisp_device {
bool is_first_double;
bool is_probe_end;
bool is_frame_double;
bool is_suspend;
bool suspend_sync;
struct rkisp_vicap_input vicap_in;
@@ -304,4 +312,8 @@ rkisp_unite_clear_bits(struct rkisp_device *dev, u32 reg, u32 mask,
rkisp_next_clear_bits(dev, reg, mask, is_direct);
}
static inline bool rkisp_link_sensor(u32 isp_inp)
{
return isp_inp & (INP_CSI | INP_DVP | INP_LVDS);
}
#endif

View File

@@ -35,6 +35,12 @@
* rkisp_hw
*/
struct backup_reg {
const u32 base;
const u32 shd;
u32 val;
};
struct isp_irqs_data {
const char *name;
irqreturn_t (*irq_hdl)(int irq, void *ctx);
@@ -302,6 +308,192 @@ int rkisp_register_irq(struct rkisp_hw_dev *hw_dev)
return 0;
}
void rkisp_hw_reg_save(struct rkisp_hw_dev *dev)
{
void *buf = dev->sw_reg;
memcpy_fromio(buf, dev->base_addr, RKISP_ISP_SW_REG_SIZE);
if (dev->unite == ISP_UNITE_TWO) {
buf += RKISP_ISP_SW_REG_SIZE;
memcpy_fromio(buf, dev->base_next_addr, RKISP_ISP_SW_REG_SIZE);
}
}
void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev)
{
struct rkisp_device *isp = dev->isp[dev->cur_dev_id];
void __iomem *base = dev->base_addr;
void *reg_buf = dev->sw_reg;
u32 val, *reg, *reg1, i, j;
u32 self_upd_reg[] = {
ISP21_BAY3D_BASE, ISP21_DRC_BASE, ISP3X_BAY3D_CTRL,
ISP_DHAZ_CTRL, ISP3X_3DLUT_BASE, ISP_RAWAE_LITE_BASE,
RAWAE_BIG1_BASE, RAWAE_BIG2_BASE, RAWAE_BIG3_BASE,
ISP_RAWHIST_LITE_BASE, ISP_RAWHIST_BIG1_BASE,
ISP_RAWHIST_BIG2_BASE, ISP_RAWHIST_BIG3_BASE,
ISP_RAWAF_BASE, ISP_RAWAWB_BASE, ISP_LDCH_BASE,
ISP3X_CAC_BASE,
};
struct backup_reg backup[] = {
{
.base = MI_MP_WR_Y_BASE,
.shd = MI_MP_WR_Y_BASE_SHD,
}, {
.base = MI_MP_WR_CB_BASE,
.shd = MI_MP_WR_CB_BASE_SHD,
}, {
.base = MI_MP_WR_CR_BASE,
.shd = MI_MP_WR_CR_BASE_SHD,
}, {
.base = MI_SP_WR_Y_BASE,
.shd = MI_SP_WR_Y_BASE_SHD,
}, {
.base = MI_SP_WR_CB_BASE,
.shd = MI_SP_WR_CB_BASE_AD_SHD,
}, {
.base = MI_SP_WR_CR_BASE,
.shd = MI_SP_WR_CR_BASE_AD_SHD,
}, {
.base = ISP3X_MI_BP_WR_Y_BASE,
.shd = ISP3X_MI_BP_WR_Y_BASE_SHD,
}, {
.base = ISP3X_MI_BP_WR_CB_BASE,
.shd = ISP3X_MI_BP_WR_CB_BASE_SHD,
}, {
.base = ISP32_MI_MPDS_WR_Y_BASE,
.shd = ISP32_MI_MPDS_WR_Y_BASE_SHD,
}, {
.base = ISP32_MI_MPDS_WR_CB_BASE,
.shd = ISP32_MI_MPDS_WR_CB_BASE_SHD,
}, {
.base = ISP32_MI_BPDS_WR_Y_BASE,
.shd = ISP32_MI_BPDS_WR_Y_BASE_SHD,
}, {
.base = ISP32_MI_BPDS_WR_CB_BASE,
.shd = ISP32_MI_BPDS_WR_CB_BASE_SHD,
}, {
.base = MI_RAW0_WR_BASE,
.shd = MI_RAW0_WR_BASE_SHD,
}, {
.base = MI_RAW1_WR_BASE,
.shd = MI_RAW1_WR_BASE_SHD,
}, {
.base = MI_RAW2_WR_BASE,
.shd = MI_RAW2_WR_BASE_SHD,
}, {
.base = MI_RAW3_WR_BASE,
.shd = MI_RAW3_WR_BASE_SHD,
}, {
.base = MI_RAW0_RD_BASE,
.shd = MI_RAW0_RD_BASE_SHD,
}, {
.base = MI_RAW1_RD_BASE,
.shd = MI_RAW1_RD_BASE_SHD,
}, {
.base = MI_RAW2_RD_BASE,
.shd = MI_RAW2_RD_BASE_SHD,
}, {
.base = MI_GAIN_WR_BASE,
.shd = MI_GAIN_WR_BASE_SHD,
}
};
for (i = 0; i <= !!dev->unite; i++) {
if (dev->unite != ISP_UNITE_TWO && i)
break;
if (i) {
reg_buf += RKISP_ISP_SW_REG_SIZE;
base = dev->base_next_addr;
}
/* process special reg */
for (j = 0; j < ARRAY_SIZE(self_upd_reg); j++) {
reg = reg_buf + self_upd_reg[j];
*reg &= ~ISP21_SELF_FORCE_UPD;
if (self_upd_reg[j] == ISP3X_3DLUT_BASE && *reg & ISP_3DLUT_EN) {
reg = reg_buf + ISP3X_3DLUT_UPDATE;
*reg = 1;
}
}
reg = reg_buf + ISP_CTRL;
*reg &= ~(CIF_ISP_CTRL_ISP_ENABLE |
CIF_ISP_CTRL_ISP_INFORM_ENABLE |
CIF_ISP_CTRL_ISP_CFG_UPD);
reg = reg_buf + MI_WR_INIT;
*reg = 0;
reg = reg_buf + CSI2RX_CTRL0;
*reg &= ~SW_CSI2RX_EN;
for (j = 0; j < RKISP_ISP_SW_REG_SIZE; j += 4) {
/* skip table RAM */
if ((j > ISP3X_LSC_CTRL && j < ISP3X_LSC_XGRAD_01) ||
(j > ISP32_CAC_OFFSET && j < ISP3X_CAC_RO_CNT) ||
(j > ISP3X_3DLUT_UPDATE && j < ISP3X_GAIN_BASE) ||
(j == 0x4840 || j == 0x4a80 || j == 0x4b40 || j == 0x5660))
continue;
/* skip mmu range */
if (dev->isp_ver < ISP_V30 &&
j > ISP21_MI_BAY3D_RD_BASE_SHD && j < CSI2RX_CTRL0)
continue;
/* reg value of read diff to write */
if (j == ISP_MPFBC_CTRL ||
j == ISP32_ISP_AWB1_GAIN_G || j == ISP32_ISP_AWB1_GAIN_RB)
reg = isp->sw_base_addr + j;
else
reg = reg_buf + j;
writel(*reg, base + j);
}
/* config shd_reg to base_reg */
for (j = 0; j < ARRAY_SIZE(backup); j++) {
reg = reg_buf + backup[j].base;
reg1 = reg_buf + backup[j].shd;
backup[j].val = *reg;
writel(*reg1, base + backup[j].base);
}
/* update module */
reg = reg_buf + DUAL_CROP_CTRL;
if (*reg & 0xf)
writel(*reg | CIF_DUAL_CROP_CFG_UPD, base + DUAL_CROP_CTRL);
reg = reg_buf + SELF_RESIZE_CTRL;
if (*reg & 0xf) {
if (dev->isp_ver == ISP_V32_L)
writel(*reg | ISP32_SCALE_FORCE_UPD, base + ISP32_SELF_SCALE_UPDATE);
else
writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + SELF_RESIZE_CTRL);
}
reg = reg_buf + MAIN_RESIZE_CTRL;
if (*reg & 0xf)
writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + MAIN_RESIZE_CTRL);
reg = reg_buf + ISP32_BP_RESIZE_CTRL;
if (*reg & 0xf)
writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + ISP32_BP_RESIZE_CTRL);
/* update mi and isp, base_reg will update to shd_reg */
writel(CIF_MI_INIT_SOFT_UPD, base + MI_WR_INIT);
/* config base_reg */
for (j = 0; j < ARRAY_SIZE(backup); j++)
writel(backup[j].val, base + backup[j].base);
/* base_reg = shd_reg, write is base but read is shd */
val = rkisp_read_reg_cache(isp, ISP_MPFBC_HEAD_PTR);
writel(val, base + ISP_MPFBC_HEAD_PTR);
val = rkisp_read_reg_cache(isp, MI_SWS_3A_WR_BASE);
writel(val, base + MI_SWS_3A_WR_BASE);
}
rkisp_params_cfgsram(&isp->params_vdev, false);
reg = reg_buf + ISP_CTRL;
*reg |= CIF_ISP_CTRL_ISP_ENABLE |
CIF_ISP_CTRL_ISP_CFG_UPD |
CIF_ISP_CTRL_ISP_INFORM_ENABLE;
writel(*reg, dev->base_addr + ISP_CTRL);
if (dev->unite == ISP_UNITE_TWO)
writel(*reg, dev->base_next_addr + ISP_CTRL);
}
static const char * const rk3562_isp_clks[] = {
"clk_isp_core",
"aclk_isp",
@@ -733,7 +925,6 @@ static void disable_sys_clk(struct rkisp_hw_dev *dev)
static int enable_sys_clk(struct rkisp_hw_dev *dev)
{
int i, ret = -EINVAL;
unsigned long rate;
for (i = 0; i < dev->num_clks; i++) {
if (!IS_ERR(dev->clks[i])) {
@@ -743,12 +934,6 @@ static int enable_sys_clk(struct rkisp_hw_dev *dev)
}
}
if (!dev->is_assigned_clk) {
rate = dev->clk_rate_tbl[0].clk_rate * 1000000UL;
rkisp_set_clk_rate(dev->clks[0], rate);
if (dev->unite == ISP_UNITE_TWO)
rkisp_set_clk_rate(dev->clks[5], rate);
}
rkisp_soft_reset(dev, false);
isp_config_clk(dev, true);
return 0;
@@ -805,19 +990,24 @@ static int rkisp_hw_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct rkisp_hw_dev *hw_dev;
struct resource *res;
int i, ret;
int i, ret, mult = 1;
bool is_mem_reserved = true;
u32 clk_rate = 0;
match = of_match_node(rkisp_hw_of_match, node);
if (IS_ERR(match))
return PTR_ERR(match);
match_data = match->data;
hw_dev = devm_kzalloc(dev, sizeof(*hw_dev), GFP_KERNEL);
if (!hw_dev)
return -ENOMEM;
match_data = match->data;
if (match_data->unite)
mult = 2;
hw_dev->sw_reg = devm_kzalloc(dev, RKISP_ISP_SW_REG_SIZE * mult, GFP_KERNEL);
if (!hw_dev->sw_reg)
return -ENOMEM;
dev_set_drvdata(dev, hw_dev);
hw_dev->dev = dev;
hw_dev->is_thunderboot = IS_ENABLED(CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP);
@@ -995,11 +1185,23 @@ static void rkisp_hw_shutdown(struct platform_device *pdev)
static int __maybe_unused rkisp_runtime_suspend(struct device *dev)
{
struct rkisp_hw_dev *hw_dev = dev_get_drvdata(dev);
int i;
hw_dev->dev_link_num = 0;
hw_dev->is_single = true;
hw_dev->is_multi_overflow = false;
hw_dev->is_frm_buf = false;
hw_dev->is_idle = true;
if (dev->power.runtime_status) {
hw_dev->dev_link_num = 0;
hw_dev->is_single = true;
hw_dev->is_multi_overflow = false;
hw_dev->is_frm_buf = false;
} else {
/* system suspend */
for (i = 0; i < hw_dev->dev_num; i++) {
if (hw_dev->isp_size[i].is_on) {
rkisp_hw_reg_save(hw_dev);
break;
}
}
}
disable_sys_clk(hw_dev);
return pinctrl_pm_select_sleep_state(dev);
}
@@ -1062,28 +1264,45 @@ static int __maybe_unused rkisp_runtime_resume(struct device *dev)
return ret;
enable_sys_clk(hw_dev);
for (i = 0; i < hw_dev->dev_num; i++) {
isp = hw_dev->isp[i];
if (!isp || !isp->sw_base_addr)
continue;
buf = isp->sw_base_addr;
memset(buf, 0, RKISP_ISP_SW_MAX_SIZE * mult);
memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE);
if (hw_dev->unite) {
buf += RKISP_ISP_SW_MAX_SIZE;
base = hw_dev->base_next_addr;
memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE);
if (dev->power.runtime_status) {
if (!hw_dev->is_assigned_clk) {
unsigned long rate = hw_dev->clk_rate_tbl[0].clk_rate * 1000000UL;
rkisp_set_clk_rate(hw_dev->clks[0], rate);
if (hw_dev->unite == ISP_UNITE_TWO)
rkisp_set_clk_rate(hw_dev->clks[5], rate);
}
for (i = 0; i < hw_dev->dev_num; i++) {
isp = hw_dev->isp[i];
if (!isp || !isp->sw_base_addr)
continue;
buf = isp->sw_base_addr;
memset(buf, 0, RKISP_ISP_SW_MAX_SIZE * mult);
memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE);
if (hw_dev->unite) {
buf += RKISP_ISP_SW_MAX_SIZE;
base = hw_dev->base_next_addr;
memcpy_fromio(buf, base, RKISP_ISP_SW_REG_SIZE);
}
default_sw_reg_flag(hw_dev->isp[i]);
}
rkisp_hw_enum_isp_size(hw_dev);
hw_dev->monitor.is_en = rkisp_monitor;
} else {
/* system resume */
for (i = 0; i < hw_dev->dev_num; i++) {
if (hw_dev->isp_size[i].is_on) {
rkisp_hw_reg_restore(hw_dev);
break;
}
}
default_sw_reg_flag(hw_dev->isp[i]);
}
rkisp_hw_enum_isp_size(hw_dev);
hw_dev->monitor.is_en = rkisp_monitor;
return 0;
}
static const struct dev_pm_ops rkisp_hw_pm_ops = {
SET_RUNTIME_PM_OPS(rkisp_runtime_suspend,
rkisp_runtime_resume, NULL)
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume)
SET_RUNTIME_PM_OPS(rkisp_runtime_suspend, rkisp_runtime_resume, NULL)
};
static struct platform_driver rkisp_hw_drv = {

View File

@@ -29,7 +29,6 @@ struct rkisp_monitor {
struct rkisp_hw_dev *dev;
struct work_struct work;
struct completion cmpl;
int (*reset_handle)(struct rkisp_device *dev);
u32 state;
u8 retry;
bool is_en;
@@ -53,6 +52,7 @@ struct rkisp_hw_dev {
struct platform_device *pdev;
struct device *dev;
struct regmap *grf;
void *sw_reg;
void __iomem *base_addr;
void __iomem *base_next_addr;
struct clk *clks[RKISP_MAX_BUS_CLK];
@@ -110,4 +110,6 @@ struct rkisp_hw_dev {
int rkisp_register_irq(struct rkisp_hw_dev *dev);
void rkisp_soft_reset(struct rkisp_hw_dev *dev, bool is_secure);
void rkisp_hw_enum_isp_size(struct rkisp_hw_dev *hw_dev);
void rkisp_hw_reg_save(struct rkisp_hw_dev *dev);
void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev);
#endif

View File

@@ -13,6 +13,9 @@
#define RKISP_VICAP_CMD_RX_BUFFER_FREE \
_IOW('V', BASE_VIDIOC_PRIVATE + 2, struct rkisp_rx_buf)
#define RKISP_VICAP_CMD_QUICK_STREAM \
_IOW('V', BASE_VIDIOC_PRIVATE + 3, int)
#define RKISP_VICAP_BUF_CNT 3
#define RKISP_VICAP_BUF_CNT_MAX 8
#define RKISP_RX_BUF_POOL_MAX (RKISP_VICAP_BUF_CNT_MAX * 3)

View File

@@ -185,6 +185,28 @@ static void rkisp_params_vb2_buf_queue(struct vb2_buffer *vb)
spin_lock_irqsave(&params_vdev->config_lock, flags);
list_add_tail(&params_buf->queue, &params_vdev->params);
spin_unlock_irqrestore(&params_vdev->config_lock, flags);
if (params_vdev->dev->is_first_double) {
struct isp32_isp_params_cfg *params = params_buf->vaddr[0];
struct rkisp_buffer *buf;
if (!(params->module_cfg_update & ISP32_MODULE_RTT_FST))
return;
spin_lock_irqsave(&params_vdev->config_lock, flags);
while (!list_empty(&params_vdev->params)) {
buf = list_first_entry(&params_vdev->params,
struct rkisp_buffer, queue);
if (buf == params_buf)
break;
list_del(&buf->queue);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
}
spin_unlock_irqrestore(&params_vdev->config_lock, flags);
dev_info(params_vdev->dev->dev,
"first params:%d for rtt resume\n", params->frame_id);
params_vdev->dev->is_first_double = false;
rkisp_trigger_read_back(params_vdev->dev, false, false, false);
}
}
static void rkisp_params_vb2_stop_streaming(struct vb2_queue *vq)
@@ -368,15 +390,16 @@ void rkisp_params_cfg(struct rkisp_isp_params_vdev *params_vdev, u32 frame_id)
params_vdev->ops->param_cfg(params_vdev, frame_id, RKISP_PARAMS_IMD);
}
void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev)
void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev, bool is_check)
{
if (params_vdev->dev->procfs.mode & RKISP_PROCFS_FIL_SW)
return;
/* multi device to switch sram config */
if (params_vdev->dev->hw_dev->is_single)
return;
if (is_check) {
if (params_vdev->dev->procfs.mode & RKISP_PROCFS_FIL_SW)
return;
/* multi device to switch sram config */
if (params_vdev->dev->hw_dev->is_single)
return;
}
if (params_vdev->ops->param_cfgsram)
params_vdev->ops->param_cfgsram(params_vdev);
}

View File

@@ -140,7 +140,7 @@ void rkisp_params_isr(struct rkisp_isp_params_vdev *params_vdev, u32 isp_mis);
void rkisp_params_cfg(struct rkisp_isp_params_vdev *params_vdev, u32 frame_id);
void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev);
void rkisp_params_cfgsram(struct rkisp_isp_params_vdev *params_vdev, bool is_check);
void rkisp_params_get_meshbuf_inf(struct rkisp_isp_params_vdev *params_vdev, void *meshbuf);
int rkisp_params_set_meshbuf_size(struct rkisp_isp_params_vdev *params_vdev, void *meshsize);
void rkisp_params_meshbuf_free(struct rkisp_isp_params_vdev *params_vdev, u64 id);

View File

@@ -460,10 +460,9 @@ isp_lsc_matrix_cfg_sram(struct rkisp_isp_params_vdev *params_vdev,
{
int i, j;
unsigned int sram_addr;
unsigned int data;
unsigned int data = rkisp_ioread32(params_vdev, ISP_LSC_CTRL);
if (is_check &&
!(rkisp_ioread32(params_vdev, ISP_LSC_CTRL) & ISP_LSC_EN))
if (is_check && (data & ISP_LSC_LUT_EN || !(data & ISP_LSC_EN)))
return;
/* CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */
@@ -603,12 +602,13 @@ isp_lsc_config(struct rkisp_isp_params_vdev *params_vdev,
* readback mode lsc lut AHB config to sram, once for single device,
* need record to switch for multi-device.
*/
if (!IS_HDR_RDBK(dev->rd_mode))
if (!IS_HDR_RDBK(dev->rd_mode)) {
isp_lsc_matrix_cfg_ddr(params_vdev, arg);
else if (dev->hw_dev->is_single)
isp_lsc_matrix_cfg_sram(params_vdev, arg, false);
else
} else {
if (dev->hw_dev->is_single)
isp_lsc_matrix_cfg_sram(params_vdev, arg, false);
params_rec->others.lsc_cfg = *arg;
}
for (i = 0; i < 4; i++) {
/* program x size tables */
@@ -1327,8 +1327,8 @@ isp_rawawb_cfg_sram(struct rkisp_isp_params_vdev *params_vdev,
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 |
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 |
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 |
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24,
rkisp_iowrite32(params_vdev, val, ISP21_RAWAWB_WRAM_DATA_BASE);
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24;
rkisp_write(params_vdev->dev, ISP21_RAWAWB_WRAM_DATA_BASE, val, true);
}
}
@@ -2143,10 +2143,9 @@ isp_rawawb_config(struct rkisp_isp_params_vdev *params_vdev,
if (params_vdev->dev->hw_dev->is_single)
isp_rawawb_cfg_sram(params_vdev, arg, false);
else
memcpy(arg_rec->sw_rawawb_wp_blk_wei_w,
arg->sw_rawawb_wp_blk_wei_w,
ISP21_RAWAWB_WEIGHT_NUM);
memcpy(arg_rec->sw_rawawb_wp_blk_wei_w,
arg->sw_rawawb_wp_blk_wei_w,
ISP21_RAWAWB_WEIGHT_NUM);
/* avoid to override the old enable value */
value = rkisp_ioread32(params_vdev, ISP21_RAWAWB_CTRL);
@@ -2370,8 +2369,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev,
if (dev->hw_dev->is_single)
isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false);
else
*arg_rec = *arg;
*arg_rec = *arg;
}
static void

View File

@@ -536,10 +536,9 @@ isp_lsc_matrix_cfg_sram(struct rkisp_isp_params_vdev *params_vdev,
{
int i, j;
unsigned int sram_addr;
unsigned int data;
unsigned int data = rkisp_ioread32(params_vdev, ISP_LSC_CTRL);
if (is_check &&
!(rkisp_ioread32(params_vdev, ISP_LSC_CTRL) & ISP_LSC_EN))
if (is_check && (data & ISP_LSC_LUT_EN || !(data & ISP_LSC_EN)))
return;
/* CIF_ISP_LSC_TABLE_ADDRESS_153 = ( 17 * 18 ) >> 1 */
@@ -679,12 +678,13 @@ isp_lsc_config(struct rkisp_isp_params_vdev *params_vdev,
* readback mode lsc lut AHB config to sram, once for single device,
* need record to switch for multi-device.
*/
if (!IS_HDR_RDBK(dev->rd_mode))
if (!IS_HDR_RDBK(dev->rd_mode)) {
isp_lsc_matrix_cfg_ddr(params_vdev, arg);
else if (dev->hw_dev->is_single)
isp_lsc_matrix_cfg_sram(params_vdev, arg, false);
else
} else {
params_rec->others.lsc_cfg = *arg;
if (dev->hw_dev->is_single)
isp_lsc_matrix_cfg_sram(params_vdev, arg, false);
}
for (i = 0; i < 4; i++) {
/* program x size tables */
@@ -2910,8 +2910,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev,
if (dev->hw_dev->is_single)
isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false);
else
*arg_rec = *arg;
*arg_rec = *arg;
}
static void

View File

@@ -555,11 +555,11 @@ isp_lsc_matrix_cfg_sram(struct rkisp_isp_params_vdev *params_vdev,
bool is_check, u32 id)
{
struct rkisp_device *dev = params_vdev->dev;
u32 sram_addr, data, table;
u32 data = isp3_param_read(params_vdev, ISP3X_LSC_CTRL, id);
u32 sram_addr, table;
int i, j;
if (is_check &&
!(isp3_param_read(params_vdev, ISP3X_LSC_CTRL, id) & ISP_LSC_EN))
if (is_check && (data & ISP3X_LSC_LUT_EN || !(data & ISP_LSC_EN)))
return;
table = isp3_param_read_direct(params_vdev, ISP3X_LSC_STATUS);
@@ -643,12 +643,13 @@ isp_lsc_config(struct rkisp_isp_params_vdev *params_vdev,
* readback mode lsc lut AHB config to sram, once for single device,
* need record to switch for multi-device.
*/
if (!IS_HDR_RDBK(dev->rd_mode))
if (!IS_HDR_RDBK(dev->rd_mode)) {
isp_lsc_matrix_cfg_ddr(params_vdev, arg);
else if (dev->hw_dev->is_single)
isp_lsc_matrix_cfg_sram(params_vdev, arg, false, id);
else
} else {
if (dev->hw_dev->is_single)
isp_lsc_matrix_cfg_sram(params_vdev, arg, false, id);
params_rec->others.lsc_cfg = *arg;
}
} else {
/* two lsc sram table */
params_rec->others.lsc_cfg = *arg;
@@ -1576,20 +1577,19 @@ static void
isp_rawawb_cfg_sram(struct rkisp_isp_params_vdev *params_vdev,
const struct isp32_rawawb_meas_cfg *arg, bool is_check, u32 id)
{
u32 i, val = ISP32_MODULE_EN;
u32 i, val = isp3_param_read(params_vdev, ISP3X_RAWAWB_CTRL, id);
if (params_vdev->dev->isp_ver == ISP_V32 && is_check &&
!(isp3_param_read(params_vdev, ISP3X_RAWAWB_CTRL, id) & val))
if (params_vdev->dev->isp_ver != ISP_V32 ||
(is_check && !(val & ISP32_MODULE_EN)))
return;
for (i = 0; i < ISP32_RAWAWB_WEIGHT_NUM / 5; i++) {
isp3_param_write_direct(params_vdev,
(arg->wp_blk_wei_w[5 * i] & 0x3f) |
(arg->wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 |
(arg->wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 |
(arg->wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 |
(arg->wp_blk_wei_w[5 * i + 4] & 0x3f) << 24,
ISP3X_RAWAWB_WRAM_DATA_BASE);
val = (arg->wp_blk_wei_w[5 * i] & 0x3f) |
(arg->wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 |
(arg->wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 |
(arg->wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 |
(arg->wp_blk_wei_w[5 * i + 4] & 0x3f) << 24;
isp3_param_write_direct(params_vdev, val, ISP3X_RAWAWB_WRAM_DATA_BASE);
}
}
@@ -2255,9 +2255,7 @@ isp_rawawb_config(struct rkisp_isp_params_vdev *params_vdev,
if (params_vdev->dev->isp_ver == ISP_V32) {
if (params_vdev->dev->hw_dev->is_single)
isp_rawawb_cfg_sram(params_vdev, arg, false, id);
else
memcpy(arg_rec->wp_blk_wei_w, arg->wp_blk_wei_w,
ISP32_RAWAWB_WEIGHT_NUM);
memcpy(arg_rec->wp_blk_wei_w, arg->wp_blk_wei_w, ISP32_RAWAWB_WEIGHT_NUM);
} else {
for (i = 0; i < ISP32L_RAWAWB_WEIGHT_NUM; i++)
isp3_param_write(params_vdev, arg->win_weight[i],
@@ -2503,8 +2501,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev,
if (dev->hw_dev->is_single)
isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false, id);
else
*arg_rec = *arg;
*arg_rec = *arg;
}
static void

View File

@@ -1430,13 +1430,12 @@ isp_rawawb_cfg_sram(struct rkisp_isp_params_vdev *params_vdev,
return;
for (i = 0; i < ISP3X_RAWAWB_WEIGHT_NUM / 5; i++) {
isp3_param_write(params_vdev,
(arg->sw_rawawb_wp_blk_wei_w[5 * i] & 0x3f) << 0 |
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 |
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 |
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 |
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24,
ISP3X_RAWAWB_WRAM_DATA_BASE, id);
val = (arg->sw_rawawb_wp_blk_wei_w[5 * i] & 0x3f) << 0 |
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 1] & 0x3f) << 6 |
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 2] & 0x3f) << 12 |
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 3] & 0x3f) << 18 |
(arg->sw_rawawb_wp_blk_wei_w[5 * i + 4] & 0x3f) << 24;
isp3_param_write_direct(params_vdev, val, ISP3X_RAWAWB_WRAM_DATA_BASE, id);
}
}
@@ -2288,10 +2287,9 @@ isp_rawawb_config(struct rkisp_isp_params_vdev *params_vdev,
if (params_vdev->dev->hw_dev->is_single)
isp_rawawb_cfg_sram(params_vdev, arg, false, id);
else
memcpy(arg_rec->sw_rawawb_wp_blk_wei_w,
arg->sw_rawawb_wp_blk_wei_w,
ISP3X_RAWAWB_WEIGHT_NUM);
memcpy(arg_rec->sw_rawawb_wp_blk_wei_w,
arg->sw_rawawb_wp_blk_wei_w,
ISP3X_RAWAWB_WEIGHT_NUM);
/* avoid to override the old enable value */
value = isp3_param_read(params_vdev, ISP3X_RAWAWB_CTRL, id);
@@ -2502,8 +2500,7 @@ isp_rawhstbig_config(struct rkisp_isp_params_vdev *params_vdev,
if (dev->hw_dev->is_single)
isp_rawhstbig_cfg_sram(params_vdev, arg, blk_no, false, id);
else
*arg_rec = *arg;
*arg_rec = *arg;
}
static void

View File

@@ -229,6 +229,11 @@ int rkisp_rockit_buf_done(struct rkisp_stream *stream, int cmd)
rockit_cfg->frame.u64PTS = stream->curr_buf->vb.vb2_buf.timestamp;
rockit_cfg->frame.u32TimeRef = stream->curr_buf->vb.sequence;
v4l2_dbg(2, rkisp_debug, &dev->v4l2_dev,
"%s stream:%d seq:%d buf:0x%x done\n",
__func__, stream->id,
stream->curr_buf->vb.sequence,
stream->curr_buf->buff_addr[0]);
} else {
if (stream->ispdev->cap_dev.wrap_line &&
stream->id == RKISP_STREAM_MP) {

View File

@@ -628,6 +628,9 @@ rkisp_stats_send_meas(struct rkisp_isp_stats_vdev *stats_vdev,
ops->get_vsm_stats(stats_vdev, cur_stat_buf);
}
if (cur_stat_buf && stats_vdev->dev->is_first_double)
cur_stat_buf->meas_type |= ISP32_STAT_RTT_FST;
if (is_dummy) {
spin_lock_irqsave(&stats_vdev->rd_lock, flags);
if (!list_empty(&stats_vdev->stat)) {

View File

@@ -87,12 +87,6 @@
static void rkisp_config_cmsk(struct rkisp_device *dev);
struct backup_reg {
const u32 base;
const u32 shd;
u32 val;
};
static inline struct rkisp_device *sd_to_isp_dev(struct v4l2_subdev *sd)
{
return container_of(sd->v4l2_dev, struct rkisp_device, v4l2_dev);
@@ -717,7 +711,7 @@ void rkisp_trigger_read_back(struct rkisp_device *dev, u8 dma2frm, u32 mode, boo
params_vdev->rdbk_times = dma2frm + 1;
run_next:
rkisp_params_cfgsram(params_vdev);
rkisp_params_cfgsram(params_vdev, true);
stats_vdev->rdbk_drop = false;
if (dev->is_frame_double) {
is_upd = true;
@@ -866,6 +860,9 @@ static void rkisp_fast_switch_rx_buf(struct rkisp_device *dev, bool is_current)
struct rkisp_buffer *buf;
u32 i, val;
if (!dev->is_rtt_first)
return;
for (i = RKISP_STREAM_RAWRD0; i < RKISP_MAX_DMARX_STREAM; i++) {
stream = &dev->dmarx_dev.stream[i];
if (!stream->ops)
@@ -930,11 +927,16 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd)
goto end;
if (!IS_HDR_RDBK(dev->rd_mode))
goto end;
if (dev->is_suspend) {
if (dev->suspend_sync)
complete(&dev->pm_cmpl);
goto end;
}
for (i = 0; i < hw->dev_num; i++) {
isp = hw->isp[i];
if (!isp ||
(isp && !(isp->isp_state & ISP_START)))
(isp && (!(isp->isp_state & ISP_START) || isp->is_suspend)))
continue;
rkisp_rdbk_trigger_event(isp, T_CMD_LEN, &len[i]);
if (max < len[i]) {
@@ -944,7 +946,7 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd)
}
/* wait 2 frame to start isp for fast */
if (dev->is_pre_on && max == 1 && !atomic_read(&dev->isp_sdev.frm_sync_seq))
if (dev->is_rtt_first && max == 1 && !atomic_read(&dev->isp_sdev.frm_sync_seq))
goto end;
if (max) {
@@ -990,7 +992,7 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd)
/* first frame handle twice for thunderboot
* first output stats to AIQ and wait new params to run second
*/
if (isp->is_pre_on && t.frame_id == 0) {
if (isp->is_rtt_first && t.frame_id == 0) {
isp->is_first_double = true;
isp->skip_frame = 1;
if (hw->unite != ISP_UNITE_ONE) {
@@ -998,6 +1000,8 @@ static void rkisp_rdbk_trigger_handle(struct rkisp_device *dev, u32 cmd)
isp->is_frame_double = false;
}
rkisp_fast_switch_rx_buf(isp, false);
} else {
isp->is_rtt_first = false;
}
isp->params_vdev.rdbk_times = isp->sw_rd_cnt + 1;
}
@@ -1076,6 +1080,7 @@ void rkisp_check_idle(struct rkisp_device *dev, u32 irq)
if (dev->is_first_double) {
rkisp_fast_switch_rx_buf(dev, true);
dev->is_rtt_first = false;
dev->skip_frame = 0;
dev->irq_ends = 0;
return;
@@ -1167,86 +1172,19 @@ static void rkisp_config_ism(struct rkisp_device *dev)
rkisp_write(dev, CIF_ISP_IS_CTRL, 1, false);
}
static int rkisp_reset_handle_v2x(struct rkisp_device *dev)
static int rkisp_reset_handle(struct rkisp_device *dev)
{
void __iomem *base = dev->base_addr;
void *reg_buf = NULL;
u32 *reg, *reg1, i;
struct backup_reg backup[] = {
{
.base = MI_MP_WR_Y_BASE,
.shd = MI_MP_WR_Y_BASE_SHD,
}, {
.base = MI_MP_WR_CB_BASE,
.shd = MI_MP_WR_CB_BASE_SHD,
}, {
.base = MI_MP_WR_CR_BASE,
.shd = MI_MP_WR_CR_BASE_SHD,
}, {
.base = MI_SP_WR_Y_BASE,
.shd = MI_SP_WR_Y_BASE_SHD,
}, {
.base = MI_SP_WR_CB_BASE,
.shd = MI_SP_WR_CB_BASE_AD_SHD,
}, {
.base = MI_SP_WR_CR_BASE,
.shd = MI_SP_WR_CR_BASE_AD_SHD,
}, {
.base = MI_RAW0_WR_BASE,
.shd = MI_RAW0_WR_BASE_SHD,
}, {
.base = MI_RAW1_WR_BASE,
.shd = MI_RAW1_WR_BASE_SHD,
}, {
.base = MI_RAW2_WR_BASE,
.shd = MI_RAW2_WR_BASE_SHD,
}, {
.base = MI_RAW3_WR_BASE,
.shd = MI_RAW3_WR_BASE_SHD,
}, {
.base = MI_RAW0_RD_BASE,
.shd = MI_RAW0_RD_BASE_SHD,
}, {
.base = MI_RAW1_RD_BASE,
.shd = MI_RAW1_RD_BASE_SHD,
}, {
.base = MI_RAW2_RD_BASE,
.shd = MI_RAW2_RD_BASE_SHD,
}, {
.base = MI_GAIN_WR_BASE,
.shd = MI_GAIN_WR_BASE_SHD,
}
};
reg_buf = kzalloc(RKISP_ISP_SW_REG_SIZE, GFP_KERNEL);
if (!reg_buf)
return -ENOMEM;
u32 val;
dev_info(dev->dev, "%s enter\n", __func__);
rkisp_hw_reg_save(dev->hw_dev);
memcpy_fromio(reg_buf, base, RKISP_ISP_SW_REG_SIZE);
rkisp_soft_reset(dev->hw_dev, true);
/* process special reg */
reg = reg_buf + ISP_CTRL;
*reg &= ~(CIF_ISP_CTRL_ISP_ENABLE |
CIF_ISP_CTRL_ISP_INFORM_ENABLE |
CIF_ISP_CTRL_ISP_CFG_UPD);
reg = reg_buf + MI_WR_INIT;
*reg = 0;
reg = reg_buf + CSI2RX_CTRL0;
*reg &= ~SW_CSI2RX_EN;
/* skip mmu range */
memcpy_toio(base, reg_buf, ISP21_MI_BAY3D_RD_BASE_SHD);
memcpy_toio(base + CSI2RX_CTRL0, reg_buf + CSI2RX_CTRL0,
RKISP_ISP_SW_REG_SIZE - CSI2RX_CTRL0);
/* config shd_reg to base_reg */
for (i = 0; i < ARRAY_SIZE(backup); i++) {
reg = reg_buf + backup[i].base;
reg1 = reg_buf + backup[i].shd;
backup[i].val = *reg;
writel(*reg1, base + backup[i].base);
}
rkisp_hw_reg_restore(dev->hw_dev);
val = CIF_ISP_DATA_LOSS | CIF_ISP_PIC_SIZE_ERROR;
rkisp_unite_set_bits(dev, CIF_ISP_IMSC, 0, val, true);
/* clear state */
dev->isp_err_cnt = 0;
@@ -1254,40 +1192,12 @@ static int rkisp_reset_handle_v2x(struct rkisp_device *dev)
rkisp_set_state(&dev->isp_state, ISP_FRAME_END);
dev->hw_dev->monitor.state = ISP_FRAME_END;
/* update module */
reg = reg_buf + DUAL_CROP_CTRL;
if (*reg & 0xf)
writel(*reg | CIF_DUAL_CROP_CFG_UPD, base + DUAL_CROP_CTRL);
reg = reg_buf + SELF_RESIZE_CTRL;
if (*reg & 0xf)
writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + SELF_RESIZE_CTRL);
reg = reg_buf + MAIN_RESIZE_CTRL;
if (*reg & 0xf)
writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + MAIN_RESIZE_CTRL);
/* update mi and isp, base_reg will update to shd_reg */
force_cfg_update(dev);
reg = reg_buf + ISP_CTRL;
*reg |= CIF_ISP_CTRL_ISP_ENABLE |
CIF_ISP_CTRL_ISP_INFORM_ENABLE |
CIF_ISP_CTRL_ISP_CFG_UPD;
writel(*reg, base + ISP_CTRL);
udelay(50);
/* config base_reg */
for (i = 0; i < ARRAY_SIZE(backup); i++)
writel(backup[i].val, base + backup[i].base);
/* mpfbc base_reg = shd_reg, write is base but read is shd */
if (dev->isp_ver == ISP_V20)
writel(rkisp_read_reg_cache(dev, ISP_MPFBC_HEAD_PTR),
base + ISP_MPFBC_HEAD_PTR);
rkisp_set_bits(dev, CIF_ISP_IMSC, 0, CIF_ISP_DATA_LOSS | CIF_ISP_PIC_SIZE_ERROR, true);
if (IS_HDR_RDBK(dev->hdr.op_mode)) {
if (!dev->hw_dev->is_idle)
rkisp_trigger_read_back(dev, 1, 0, true);
else
rkisp_rdbk_trigger_event(dev, T_CMD_QUEUE, NULL);
}
kfree(reg_buf);
dev_info(dev->dev, "%s exit\n", __func__);
return 0;
}
@@ -1301,11 +1211,6 @@ static void rkisp_restart_monitor(struct work_struct *work)
struct rkisp_pipeline *p;
int ret, i, j, timeout = 5, mipi_irq_cnt = 0;
if (!monitor->reset_handle) {
monitor->is_en = false;
return;
}
dev_info(hw->dev, "%s enter\n", __func__);
while (!(monitor->state & ISP_STOP) && monitor->is_en) {
ret = wait_for_completion_timeout(&monitor->cmpl,
@@ -1363,7 +1268,7 @@ static void rkisp_restart_monitor(struct work_struct *work)
/* restart isp */
isp = hw->isp[hw->cur_dev_id];
ret = monitor->reset_handle(isp);
ret = rkisp_reset_handle(isp);
if (ret) {
monitor->is_en = false;
break;
@@ -1400,9 +1305,6 @@ static void rkisp_monitor_init(struct rkisp_device *dev)
struct rkisp_monitor *monitor = &dev->hw_dev->monitor;
monitor->dev = dev->hw_dev;
monitor->reset_handle = NULL;
if (dev->isp_ver == ISP_V20 || dev->isp_ver == ISP_V21)
monitor->reset_handle = rkisp_reset_handle_v2x;
init_completion(&monitor->cmpl);
INIT_WORK(&monitor->work, rkisp_restart_monitor);
@@ -3105,7 +3007,8 @@ static int rkisp_rx_buf_pool_init(struct rkisp_device *dev,
pool->dbufs = dbufs;
v4l2_dbg(1, rkisp_debug, &dev->v4l2_dev,
"%s type:0x%x dbufs[%d]:%p", __func__, dbufs->type, i, dbufs);
"%s type:0x%x first:%d dbufs[%d]:%p", __func__,
dbufs->type, dbufs->is_first, i, dbufs);
if (dbufs->is_resmem) {
dma = dbufs->dma;
@@ -3491,7 +3394,7 @@ static long rkisp_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
rkisp_get_info(isp_dev, arg);
break;
case RKISP_CMD_GET_TB_HEAD_V32:
if (isp_dev->tb_head.complete != RKISP_TB_OK || !isp_dev->is_pre_on) {
if (isp_dev->tb_head.complete != RKISP_TB_OK) {
ret = -EINVAL;
break;
}
@@ -3811,6 +3714,7 @@ int rkisp_register_isp_subdev(struct rkisp_device *isp_dev,
atomic_set(&isp_sdev->frm_sync_seq, 0);
rkisp_monitor_init(isp_dev);
INIT_WORK(&isp_dev->rdbk_work, rkisp_rdbk_work);
init_completion(&isp_dev->pm_cmpl);
return 0;
err_cleanup_media_entity:
media_entity_cleanup(&sd->entity);
@@ -3850,8 +3754,7 @@ void rkisp_unregister_isp_subdev(struct rkisp_device *isp_dev)
(cond) ? 0 : -ETIMEDOUT; \
})
#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP
static void rkisp_save_tb_info(struct rkisp_device *isp_dev)
void rkisp_save_tb_info(struct rkisp_device *isp_dev)
{
struct rkisp_isp_params_vdev *params_vdev = &isp_dev->params_vdev;
void *resmem_va = phys_to_virt(isp_dev->resmem_pa);
@@ -3871,7 +3774,8 @@ static void rkisp_save_tb_info(struct rkisp_device *isp_dev)
if (size && size < isp_dev->resmem_size) {
dma_sync_single_for_cpu(isp_dev->dev, isp_dev->resmem_addr + offset,
size, DMA_FROM_DEVICE);
params_vdev->is_first_cfg = true;
if (isp_dev->is_rtt_first)
params_vdev->is_first_cfg = true;
if (isp_dev->isp_ver == ISP_V32) {
struct rkisp32_thunderboot_resmem_head *tmp = resmem_va + offset;
@@ -3883,7 +3787,7 @@ static void rkisp_save_tb_info(struct rkisp_device *isp_dev)
tmp->cfg.module_ens,
tmp->cfg.module_cfg_update);
}
if (param)
if (param && (isp_dev->isp_state & ISP_STOP))
params_vdev->ops->save_first_param(params_vdev, param);
} else if (size > isp_dev->resmem_size) {
v4l2_err(&isp_dev->v4l2_dev,
@@ -3894,6 +3798,7 @@ static void rkisp_save_tb_info(struct rkisp_device *isp_dev)
memcpy(&isp_dev->tb_head, head, sizeof(*head));
}
#ifdef CONFIG_VIDEO_ROCKCHIP_THUNDER_BOOT_ISP
void rkisp_chk_tb_over(struct rkisp_device *isp_dev)
{
struct rkisp_isp_params_vdev *params_vdev = &isp_dev->params_vdev;
@@ -3941,11 +3846,10 @@ void rkisp_chk_tb_over(struct rkisp_device *isp_dev)
end:
head = &isp_dev->tb_head;
v4l2_info(&isp_dev->v4l2_dev,
"thunderboot info: %d, %d, %d, %d, %d, %d | %d %d\n",
"tb info en:%d comp:%d cnt:%d w:%d h:%d cam:%d idx:%d\n",
head->enable,
head->complete,
head->frm_total,
head->hdr_mode,
head->width,
head->height,
head->camera_num,

View File

@@ -153,6 +153,8 @@ void rkisp_chk_tb_over(struct rkisp_device *isp_dev);
static inline void rkisp_chk_tb_over(struct rkisp_device *isp_dev) {}
#endif
void rkisp_save_tb_info(struct rkisp_device *isp_dev);
void rkisp_mipi_isr(unsigned int mipi_mis, struct rkisp_device *dev);
void rkisp_mipi_v13_isr(unsigned int err1, unsigned int err2,

View File

@@ -334,7 +334,8 @@ int serdes_set_pinctrl_default(struct serdes *serdes);
int serdes_set_pinctrl_sleep(struct serdes *serdes);
int serdes_device_suspend(struct serdes *serdes);
int serdes_device_resume(struct serdes *serdes);
void serdes_device_shutdown(struct serdes *serdes);
void serdes_device_poweroff(struct serdes *serdes);
int serdes_device_shutdown(struct serdes *serdes);
int serdes_irq_init(struct serdes *serdes);
void serdes_irq_exit(struct serdes *serdes);
void serdes_auxadc_init(struct serdes *serdes);

View File

@@ -376,7 +376,7 @@ int serdes_device_resume(struct serdes *serdes)
}
EXPORT_SYMBOL_GPL(serdes_device_resume);
void serdes_device_shutdown(struct serdes *serdes)
void serdes_device_poweroff(struct serdes *serdes)
{
int ret = 0;
@@ -385,6 +385,29 @@ void serdes_device_shutdown(struct serdes *serdes)
if (ret)
dev_err(serdes->dev, "could not set sleep pins\n");
}
if (!IS_ERR(serdes->vpower)) {
ret = regulator_disable(serdes->vpower);
if (ret)
dev_err(serdes->dev, "fail to disable vpower regulator\n");
}
}
EXPORT_SYMBOL_GPL(serdes_device_poweroff);
int serdes_device_shutdown(struct serdes *serdes)
{
int ret = 0;
if (!IS_ERR(serdes->vpower)) {
ret = regulator_disable(serdes->vpower);
if (ret) {
dev_err(serdes->dev, "fail to disable vpower regulator\n");
return ret;
}
}
return ret;
}
EXPORT_SYMBOL_GPL(serdes_device_shutdown);

View File

@@ -223,6 +223,14 @@ static int serdes_i2c_probe(struct i2c_client *client,
return 0;
}
static void serdes_i2c_shutdown(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct serdes *serdes = dev_get_drvdata(dev);
serdes_device_shutdown(serdes);
}
static int serdes_i2c_prepare(struct device *dev)
{
return 0;
@@ -264,7 +272,7 @@ static int serdes_i2c_poweroff(struct device *dev)
{
struct serdes *serdes = dev_get_drvdata(dev);
serdes_device_shutdown(serdes);
serdes_device_poweroff(serdes);
return 0;
}
@@ -315,6 +323,7 @@ static struct i2c_driver serdes_i2c_driver = {
.of_match_table = of_match_ptr(serdes_of_match),
},
.probe = serdes_i2c_probe,
.shutdown = serdes_i2c_shutdown,
};
static int __init serdes_i2c_init(void)

View File

@@ -8,18 +8,78 @@
#include <linux/slab.h>
#ifdef BBT_DEBUG
#define BBT_DBG pr_err
#define bbt_dbg pr_err
#else
#define BBT_DBG(args...)
#define bbt_dbg(args...)
#endif
#define BBT_VERSION_INVALID (0xFFFFFFFFU)
#define BBT_VERSION_BLOCK_ABNORMAL (BBT_VERSION_INVALID - 1)
#define BBT_VERSION_MAX (BBT_VERSION_INVALID - 8)
struct nanddev_bbt_info {
u8 pattern[4];
unsigned int version;
u32 hash;
};
static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP)
static void bbt_dbg_hex(char *s, void *buf, u32 len)
{
print_hex_dump(KERN_WARNING, s, DUMP_PREFIX_OFFSET, 4, 4, buf, len, 0);
}
#endif
static u32 js_hash(u8 *buf, u32 len)
{
u32 hash = 0x47C6A7E6;
u32 i;
for (i = 0; i < len; i++)
hash ^= ((hash << 5) + buf[i] + (hash >> 2));
return hash;
}
static bool bbt_check_hash(u8 *buf, u32 len, u32 hash_cmp)
{
u32 hash;
/* compatible with no-hash version */
if (hash_cmp == 0 || hash_cmp == 0xFFFFFFFF)
return 1;
hash = js_hash(buf, len);
if (hash != hash_cmp)
return 0;
return 1;
}
static u32 bbt_nand_isbad_bypass(struct nand_device *nand, u32 block)
{
struct mtd_info *mtd = nanddev_to_mtd(nand);
struct nand_pos pos;
nanddev_bbt_set_block_status(nand, block, NAND_BBT_BLOCK_STATUS_UNKNOWN);
nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos);
return nanddev_isbad(nand, &pos);
}
/**
* nanddev_read_bbt() - Read the BBT (Bad Block Table)
* @nand: NAND device
* @block: bbt block address
* @update: true - get version and overwrite bbt.cache with new version;
* false - get bbt version only;
*
* Initialize the in-memory BBT.
*
* Return: 0 in case of success, a negative error code otherwise.
*/
static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update)
{
unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
@@ -30,7 +90,7 @@ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update)
u8 *data_buf, *oob_buf;
struct nanddev_bbt_info *bbt_info;
struct mtd_oob_ops ops;
int bbt_page_num;
u32 bbt_page_num;
int ret = 0;
unsigned int version = 0;
@@ -40,7 +100,7 @@ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update)
if (block >= nblocks)
return -EINVAL;
/* Aligned to page size, and even pages is better */
/* aligned to page size, and even pages is better */
bbt_page_num = (sizeof(struct nanddev_bbt_info) + nbytes +
mtd->writesize - 1) >> (ffs(mtd->writesize) - 1);
bbt_page_num = (bbt_page_num + 1) / 2 * 2;
@@ -64,29 +124,72 @@ static int nanddev_read_bbt(struct nand_device *nand, u32 block, bool update)
ops.ooblen = bbt_page_num * mtd->oobsize;
ops.ooboffs = 0;
/* store one entry for each block */
ret = mtd_read_oob(mtd, block * mtd->erasesize, &ops);
if (ret && ret != -EUCLEAN) {
pr_err("%s fail %d\n", __func__, ret);
ret = -EIO;
pr_err("read_bbt blk=%d fail=%d update=%d\n", block, ret, update);
ret = 0;
version = BBT_VERSION_BLOCK_ABNORMAL;
goto out;
} else {
ret = 0;
}
if (oob_buf[0] != 0xff && !memcmp(bbt_pattern, bbt_info->pattern, 4))
version = bbt_info->version;
/* bad block or good block without bbt */
if (memcmp(bbt_pattern, bbt_info->pattern, 4)) {
ret = 0;
goto out;
}
BBT_DBG("read_bbt from blk=%d tag=%d ver=%d\n", block, update, version);
/* good block with abnornal bbt */
if (oob_buf[0] == 0xff ||
!bbt_check_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4, bbt_info->hash)) {
pr_err("read_bbt check fail blk=%d ret=%d update=%d\n", block, ret, update);
ret = 0;
version = BBT_VERSION_BLOCK_ABNORMAL;
goto out;
}
/* good block with good bbt */
version = bbt_info->version;
bbt_dbg("read_bbt from blk=%d ver=%d update=%d\n", block, version, update);
if (update && version > nand->bbt.version) {
memcpy(nand->bbt.cache, data_buf, nbytes);
nand->bbt.version = version;
}
out:
kfree(oob_buf);
kfree(data_buf);
#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP)
bbt_dbg_hex("bbt", data_buf, nbytes + sizeof(struct nanddev_bbt_info));
if (version) {
u8 *temp_buf = kzalloc(bbt_page_num * mtd->writesize, GFP_KERNEL);
bool in_scan = nand->bbt.option & NANDDEV_BBT_SCANNED;
return ret < 0 ? -EIO : version;
if (!temp_buf)
goto out;
memcpy(temp_buf, nand->bbt.cache, nbytes);
memcpy(nand->bbt.cache, data_buf, nbytes);
if (!in_scan)
nand->bbt.option |= NANDDEV_BBT_SCANNED;
for (block = 0; block < nblocks; block++) {
ret = nanddev_bbt_get_block_status(nand, block);
if (ret != NAND_BBT_BLOCK_GOOD)
bbt_dbg("bad block[0x%x], ret=%d\n", block, ret);
}
if (!in_scan)
nand->bbt.option &= ~NANDDEV_BBT_SCANNED;
memcpy(nand->bbt.cache, temp_buf, nbytes);
kfree(temp_buf);
ret = 0;
}
#endif
out:
kfree(data_buf);
kfree(oob_buf);
return ret < 0 ? -EIO : (int)version;
}
static int nanddev_write_bbt(struct nand_device *nand, u32 block)
@@ -99,18 +202,18 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block)
u8 *data_buf, *oob_buf;
struct nanddev_bbt_info *bbt_info;
struct mtd_oob_ops ops;
int bbt_page_num;
int ret = 0;
u32 bbt_page_num;
int ret = 0, version;
struct nand_pos pos;
BBT_DBG("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version);
bbt_dbg("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version);
if (!nand->bbt.cache)
return -ENOMEM;
if (block >= nblocks)
return -EINVAL;
/* Aligned to page size, and even pages is better */
/* aligned to page size, and even pages is better */
bbt_page_num = (sizeof(struct nanddev_bbt_info) + nbytes +
mtd->writesize - 1) >> (ffs(mtd->writesize) - 1);
bbt_page_num = (bbt_page_num + 1) / 2 * 2;
@@ -130,7 +233,9 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block)
memcpy(data_buf, nand->bbt.cache, nbytes);
memcpy(bbt_info, bbt_pattern, 4);
bbt_info->version = nand->bbt.version;
bbt_info->hash = js_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4);
/* store one entry for each block */
nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos);
ret = nand->ops->erase(nand, &pos);
if (ret)
@@ -144,10 +249,23 @@ static int nanddev_write_bbt(struct nand_device *nand, u32 block)
ops.ooblen = bbt_page_num * mtd->oobsize;
ops.ooboffs = 0;
ret = mtd_write_oob(mtd, block * mtd->erasesize, &ops);
if (ret) {
nand->ops->erase(nand, &pos);
goto out;
}
version = nanddev_read_bbt(nand, block, false);
if (version != bbt_info->version) {
pr_err("bbt_write fail, blk=%d recheck fail %d-%d\n",
block, version, bbt_info->version);
nand->ops->erase(nand, &pos);
ret = -EIO;
} else {
ret = 0;
}
out:
kfree(oob_buf);
kfree(data_buf);
kfree(oob_buf);
return ret;
}
@@ -158,14 +276,30 @@ static int nanddev_bbt_format(struct nand_device *nand)
struct mtd_info *mtd = nanddev_to_mtd(nand);
struct nand_pos pos;
u32 start_block, block;
unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
BITS_PER_LONG);
start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS;
for (block = 0; block < nblocks; block++) {
nanddev_offs_to_pos(nand, block * mtd->erasesize, &pos);
if (nanddev_isbad(nand, &pos))
if (nanddev_isbad(nand, &pos)) {
if (bbt_nand_isbad_bypass(nand, 0)) {
memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache));
pr_err("bbt_format fail, test good block %d fail\n", 0);
return -EIO;
}
if (!bbt_nand_isbad_bypass(nand, block)) {
memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache));
pr_err("bbt_format fail, test bad block %d fail\n", block);
return -EIO;
}
nanddev_bbt_set_block_status(nand, block,
NAND_BBT_BLOCK_FACTORY_BAD);
}
}
for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
@@ -197,16 +331,34 @@ int nanddev_scan_bbt_in_flash(struct nand_device *nand)
for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++)
nanddev_read_bbt(nand, start_block + block, true);
nand->bbt.option |= NANDDEV_BBT_SCANNED;
if (nand->bbt.version == 0) {
nanddev_bbt_format(nand);
ret = nanddev_bbt_format(nand);
if (ret) {
nand->bbt.option = 0;
pr_err("%s format fail\n", __func__);
return ret;
}
ret = nanddev_bbt_in_flash_update(nand);
if (ret) {
nand->bbt.option = 0;
pr_err("%s fail\n", __func__);
pr_err("%s update fail\n", __func__);
return ret;
}
}
nand->bbt.option |= NANDDEV_BBT_SCANNED;
#if defined(BBT_DEBUG)
pr_err("scan_bbt success\n");
if (nand->bbt.version) {
for (block = 0; block < nblocks; block++) {
ret = nanddev_bbt_get_block_status(nand, block);
if (ret != NAND_BBT_BLOCK_GOOD)
bbt_dbg("bad block[0x%x], ret=%d\n", block, ret);
}
}
#endif
return ret;
}
@@ -222,31 +374,31 @@ EXPORT_SYMBOL_GPL(nanddev_scan_bbt_in_flash);
*/
int nanddev_bbt_in_flash_update(struct nand_device *nand)
{
struct nand_pos pos;
struct mtd_info *mtd = nanddev_to_mtd(nand);
if (nand->bbt.option & NANDDEV_BBT_SCANNED) {
unsigned int nblocks = nanddev_neraseblocks(nand);
u32 bbt_version[NANDDEV_BBT_SCAN_MAXBLOCKS];
int start_block, block;
u32 min_version, block_des;
int ret, count = 0;
int ret, count = 0, status;
start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS;
for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
ret = nanddev_bbt_get_block_status(nand, start_block + block);
if (ret == NAND_BBT_BLOCK_FACTORY_BAD) {
bbt_version[block] = 0xFFFFFFFF;
continue;
}
ret = nanddev_read_bbt(nand, start_block + block,
false);
if (ret < 0)
bbt_version[block] = 0xFFFFFFFF;
else if (ret == 0)
bbt_version[block] = 0;
status = nanddev_bbt_get_block_status(nand, start_block + block);
ret = nanddev_read_bbt(nand, start_block + block, false);
if (ret == 0 && status == NAND_BBT_BLOCK_FACTORY_BAD)
bbt_version[block] = BBT_VERSION_INVALID;
else if (ret == -EIO)
bbt_version[block] = BBT_VERSION_INVALID;
else if (ret == BBT_VERSION_BLOCK_ABNORMAL)
bbt_version[block] = ret;
else
bbt_version[block] = ret;
}
get_min_ver:
min_version = 0xFFFFFFFF;
min_version = BBT_VERSION_MAX;
block_des = 0;
for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
if (bbt_version[block] < min_version) {
@@ -255,25 +407,38 @@ get_min_ver:
}
}
/* Overwrite the BBT_VERSION_BLOCK_ABNORMAL block */
if (nand->bbt.version < min_version)
nand->bbt.version = min_version + 4;
if (block_des > 0) {
nand->bbt.version++;
ret = nanddev_write_bbt(nand, block_des);
bbt_version[block_des - start_block] = 0xFFFFFFFF;
if (ret) {
pr_err("%s blk= %d ret= %d\n", __func__,
block_des, ret);
goto get_min_ver;
} else {
count++;
if (count < 2)
goto get_min_ver;
BBT_DBG("%s success\n", __func__);
}
} else {
pr_err("%s failed\n", __func__);
pr_err("bbt_update fail, blk=%d ret= %d\n", block_des, ret);
return -EINVAL;
return -1;
}
bbt_version[block_des - start_block] = BBT_VERSION_INVALID;
count++;
if (count < 2)
goto get_min_ver;
bbt_dbg("bbt_update success\n");
} else {
pr_err("bbt_update failed\n");
ret = -1;
}
for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
if (bbt_version[block] == BBT_VERSION_BLOCK_ABNORMAL) {
block_des = start_block + block;
nanddev_offs_to_pos(nand, block_des * mtd->erasesize, &pos);
nand->ops->erase(nand, &pos);
}
}
return ret;
}
return 0;

View File

@@ -21,13 +21,119 @@
#define BBT_DBG(args...)
#endif
#define BBT_VERSION_INVALID (0xFFFFFFFFU)
#define BBT_VERSION_BLOCK_ABNORMAL (BBT_VERSION_INVALID - 1)
#define BBT_VERSION_MAX (BBT_VERSION_INVALID - 8)
struct nanddev_bbt_info {
u8 pattern[4];
unsigned int version;
u32 hash;
};
static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP)
static void bbt_dbg_hex(char *s, void *buf, u32 len)
{
print_hex_dump(KERN_WARNING, s, DUMP_PREFIX_OFFSET, 4, 4, buf, len, 0);
}
#endif
static u32 js_hash(u8 *buf, u32 len)
{
u32 hash = 0x47C6A7E6;
u32 i;
for (i = 0; i < len; i++)
hash ^= ((hash << 5) + buf[i] + (hash >> 2));
return hash;
}
static bool bbt_check_hash(u8 *buf, u32 len, u32 hash_cmp)
{
u32 hash;
/* compatible with no-hash version */
if (hash_cmp == 0 || hash_cmp == 0xFFFFFFFF)
return 1;
hash = js_hash(buf, len);
if (hash != hash_cmp)
return 0;
return 1;
}
static u32 bbt_nand_isbad_bypass(struct snand_mtd_dev *nand, u32 block)
{
struct mtd_info *mtd = snanddev_to_mtd(nand);
return sfc_nand_isbad_mtd(mtd, block * mtd->erasesize);
}
static int bbt_mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
{
int i, ret = 0, bbt_page_num, page_addr, block;
u8 *temp_buf;
bbt_page_num = ops->len >> mtd->writesize_shift;
block = from >> mtd->erasesize_shift;
temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
if (!temp_buf)
return -ENOMEM;
page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift));
for (i = 0; i < bbt_page_num; i++) {
ret = sfc_nand_read_page_raw(0, page_addr + i, (u32 *)temp_buf);
if (ret < 0) {
pr_err("%s fail %d\n", __func__, ret);
ret = -EIO;
goto out;
}
memcpy(ops->datbuf + i * mtd->writesize, temp_buf, mtd->writesize);
memcpy(ops->oobbuf + i * mtd->oobsize, temp_buf + mtd->writesize, mtd->oobsize);
}
out:
kfree(temp_buf);
return ret;
}
static int bbt_mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
{
int i, ret = 0, bbt_page_num, page_addr, block;
u8 *temp_buf;
bbt_page_num = ops->len >> mtd->writesize_shift;
block = to >> mtd->erasesize_shift;
temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
if (!temp_buf)
return -ENOMEM;
page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift));
for (i = 0; i < bbt_page_num; i++) {
memcpy(temp_buf, ops->datbuf + i * mtd->writesize, mtd->writesize);
memcpy(temp_buf + mtd->writesize, ops->oobbuf + i * mtd->oobsize, mtd->oobsize);
ret = sfc_nand_prog_page_raw(0, page_addr + i, (u32 *)temp_buf);
if (ret < 0) {
pr_err("%s fail %d\n", __func__, ret);
ret = -EIO;
goto out;
}
}
out:
kfree(temp_buf);
return ret;
}
/**
* nanddev_read_bbt() - Read the BBT (Bad Block Table)
* @nand: NAND device
@@ -37,7 +143,7 @@ static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
*
* Initialize the in-memory BBT.
*
* Return: 0 in case of success, a negative error code otherwise.
* Return: positive value means success, 0 means abnornal data, a negative error code otherwise.
*/
static int nanddev_read_bbt(struct snand_mtd_dev *nand, u32 block, bool update)
{
@@ -46,13 +152,12 @@ static int nanddev_read_bbt(struct snand_mtd_dev *nand, u32 block, bool update)
unsigned int nbytes = DIV_ROUND_UP(nblocks * bits_per_block,
BITS_PER_LONG) * sizeof(*nand->bbt.cache);
struct mtd_info *mtd = snanddev_to_mtd(nand);
u8 *data_buf, *oob_buf, *temp_buf;
u8 *data_buf, *oob_buf;
struct nanddev_bbt_info *bbt_info;
struct mtd_oob_ops ops;
u32 bbt_page_num;
int ret = 0;
unsigned int version = 0;
u32 page_addr, i;
if (!nand->bbt.cache)
return -ENOMEM;
@@ -85,37 +190,65 @@ static int nanddev_read_bbt(struct snand_mtd_dev *nand, u32 block, bool update)
ops.ooboffs = 0;
/* Store one entry for each block */
temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
if (!temp_buf) {
kfree(data_buf);
kfree(oob_buf);
return -ENOMEM;
ret = bbt_mtd_read_oob(mtd, block * mtd->erasesize, &ops);
if (ret && ret != -EUCLEAN) {
pr_err("read_bbt blk=%d fail=%d update=%d\n", block, ret, update);
ret = 0;
version = BBT_VERSION_BLOCK_ABNORMAL;
goto out;
} else {
ret = 0;
}
page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift));
for (i = 0; i < bbt_page_num; i++) {
ret = sfc_nand_read_page_raw(0, page_addr + i, (u32 *)temp_buf);
if (ret < 0) {
pr_err("%s fail %d\n", __func__, ret);
ret = -EIO;
kfree(temp_buf);
goto out;
}
memcpy(ops.datbuf + i * mtd->writesize, temp_buf, mtd->writesize);
memcpy(ops.oobbuf + i * mtd->oobsize, temp_buf + mtd->writesize, mtd->oobsize);
/* bad block or good block without bbt */
if (memcmp(bbt_pattern, bbt_info->pattern, 4)) {
ret = 0;
goto out;
}
kfree(temp_buf);
if (oob_buf[0] != 0xff && !memcmp(bbt_pattern, bbt_info->pattern, 4))
version = bbt_info->version;
/* good block with abnornal bbt */
if (oob_buf[0] == 0xff ||
!bbt_check_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4, bbt_info->hash)) {
pr_err("read_bbt check fail blk=%d ret=%d update=%d\n", block, ret, update);
ret = 0;
version = BBT_VERSION_BLOCK_ABNORMAL;
goto out;
}
BBT_DBG("read_bbt from blk=%d tag=%d ver=%d\n", block, update, version);
/* good block with good bbt */
version = bbt_info->version;
BBT_DBG("read_bbt from blk=%d ver=%d update=%d\n", block, version, update);
if (update && version > nand->bbt.version) {
memcpy(nand->bbt.cache, data_buf, nbytes);
nand->bbt.version = version;
}
#if defined(BBT_DEBUG) && defined(BBT_DEBUG_DUMP)
bbt_dbg_hex("bbt", data_buf, nbytes + sizeof(struct nanddev_bbt_info));
if (version) {
u8 *temp_buf = kzalloc(bbt_page_num * mtd->writesize, GFP_KERNEL);
bool in_scan = nand->bbt.option & NANDDEV_BBT_SCANNED;
if (!temp_buf)
goto out;
memcpy(temp_buf, nand->bbt.cache, nbytes);
memcpy(nand->bbt.cache, data_buf, nbytes);
if (!in_scan)
nand->bbt.option |= NANDDEV_BBT_SCANNED;
for (block = 0; block < nblocks; block++) {
ret = snanddev_bbt_get_block_status(nand, block);
if (ret != NAND_BBT_BLOCK_GOOD)
BBT_DBG("bad block[0x%x], ret=%d\n", block, ret);
}
if (!in_scan)
nand->bbt.option &= ~NANDDEV_BBT_SCANNED;
memcpy(nand->bbt.cache, temp_buf, nbytes);
kfree(temp_buf);
ret = 0;
}
#endif
out:
kfree(data_buf);
kfree(oob_buf);
@@ -130,12 +263,11 @@ static int nanddev_write_bbt(struct snand_mtd_dev *nand, u32 block)
unsigned int nbytes = DIV_ROUND_UP(nblocks * bits_per_block,
BITS_PER_LONG) * sizeof(*nand->bbt.cache);
struct mtd_info *mtd = snanddev_to_mtd(nand);
u8 *data_buf, *oob_buf, *temp_buf;
u8 *data_buf, *oob_buf;
struct nanddev_bbt_info *bbt_info;
struct mtd_oob_ops ops;
u32 bbt_page_num;
int ret = 0;
u32 page_addr, i;
int ret = 0, version;
BBT_DBG("write_bbt to blk=%d ver=%d\n", block, nand->bbt.version);
if (!nand->bbt.cache)
@@ -164,6 +296,7 @@ static int nanddev_write_bbt(struct snand_mtd_dev *nand, u32 block)
memcpy(data_buf, nand->bbt.cache, nbytes);
memcpy(bbt_info, bbt_pattern, 4);
bbt_info->version = nand->bbt.version;
bbt_info->hash = js_hash(data_buf, nbytes + sizeof(struct nanddev_bbt_info) - 4);
/* Store one entry for each block */
ret = sfc_nand_erase_mtd(mtd, block * mtd->erasesize);
@@ -171,34 +304,27 @@ static int nanddev_write_bbt(struct snand_mtd_dev *nand, u32 block)
goto out;
memset(&ops, 0, sizeof(struct mtd_oob_ops));
ops.mode = MTD_OPS_PLACE_OOB;
ops.datbuf = data_buf;
ops.len = bbt_page_num * mtd->writesize;
ops.oobbuf = oob_buf;
ops.ooblen = bbt_page_num * mtd->oobsize;
ops.ooboffs = 0;
temp_buf = kzalloc(mtd->writesize + mtd->oobsize, GFP_KERNEL);
if (!temp_buf) {
kfree(data_buf);
kfree(oob_buf);
return -ENOMEM;
ret = bbt_mtd_write_oob(mtd, block * mtd->erasesize, &ops);
if (ret) {
sfc_nand_erase_mtd(mtd, block * mtd->erasesize);
goto out;
}
page_addr = (u32)(block << (mtd->erasesize_shift - mtd->writesize_shift));
for (i = 0; i < bbt_page_num; i++) {
memcpy(temp_buf, ops.datbuf + i * mtd->writesize, mtd->writesize);
memcpy(temp_buf + mtd->writesize, ops.oobbuf + i * mtd->oobsize, mtd->oobsize);
ret = sfc_nand_prog_page_raw(0, page_addr + i, (u32 *)temp_buf);
if (ret < 0) {
pr_err("%s fail %d\n", __func__, ret);
ret = -EIO;
kfree(temp_buf);
goto out;
}
version = nanddev_read_bbt(nand, block, false);
if (version != bbt_info->version) {
pr_err("bbt_write fail, blk=%d recheck fail %d-%d\n",
block, version, bbt_info->version);
sfc_nand_erase_mtd(mtd, block * mtd->erasesize);
ret = -EIO;
} else {
ret = 0;
}
kfree(temp_buf);
out:
kfree(data_buf);
kfree(oob_buf);
@@ -211,13 +337,29 @@ static int nanddev_bbt_format(struct snand_mtd_dev *nand)
unsigned int nblocks = snanddev_neraseblocks(nand);
struct mtd_info *mtd = snanddev_to_mtd(nand);
u32 start_block, block;
unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
BITS_PER_LONG);
start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS;
for (block = 0; block < nblocks; block++) {
if (sfc_nand_isbad_mtd(mtd, block * mtd->erasesize))
if (sfc_nand_isbad_mtd(mtd, block * mtd->erasesize)) {
if (bbt_nand_isbad_bypass(nand, 0)) {
memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache));
pr_err("bbt_format fail, test good block %d fail\n", 0);
return -EIO;
}
if (!bbt_nand_isbad_bypass(nand, block)) {
memset(nand->bbt.cache, 0, nwords * sizeof(*nand->bbt.cache));
pr_err("bbt_format fail, test bad block %d fail\n", block);
return -EIO;
}
snanddev_bbt_set_block_status(nand, block,
NAND_BBT_BLOCK_FACTORY_BAD);
NAND_BBT_BLOCK_FACTORY_BAD);
}
}
for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
@@ -243,14 +385,34 @@ static int nanddev_scan_bbt(struct snand_mtd_dev *nand)
nand->bbt.option |= NANDDEV_BBT_SCANNED;
if (nand->bbt.version == 0) {
nanddev_bbt_format(nand);
ret = nanddev_bbt_format(nand);
if (ret) {
nand->bbt.option = 0;
pr_err("%s format fail\n", __func__);
return ret;
}
ret = snanddev_bbt_update(nand);
if (ret) {
nand->bbt.option = 0;
pr_err("%s fail\n", __func__);
pr_err("%s update fail\n", __func__);
return ret;
}
}
#if defined(BBT_DEBUG)
pr_err("scan_bbt success\n");
if (nand->bbt.version) {
for (block = 0; block < nblocks; block++) {
ret = snanddev_bbt_get_block_status(nand, block);
if (ret != NAND_BBT_BLOCK_GOOD)
BBT_DBG("bad block[0x%x], ret=%d\n", block, ret);
}
}
#endif
return ret;
}
@@ -304,32 +466,32 @@ EXPORT_SYMBOL_GPL(snanddev_bbt_cleanup);
int snanddev_bbt_update(struct snand_mtd_dev *nand)
{
#ifdef CONFIG_MTD_NAND_BBT_USING_FLASH
struct mtd_info *mtd = snanddev_to_mtd(nand);
if (nand->bbt.cache &&
nand->bbt.option & NANDDEV_BBT_USE_FLASH) {
unsigned int nblocks = snanddev_neraseblocks(nand);
u32 bbt_version[NANDDEV_BBT_SCAN_MAXBLOCKS];
int start_block, block;
u32 min_version, block_des;
int ret, count = 0;
int ret, count = 0, status;
start_block = nblocks - NANDDEV_BBT_SCAN_MAXBLOCKS;
for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
ret = snanddev_bbt_get_block_status(nand, start_block + block);
if (ret == NAND_BBT_BLOCK_FACTORY_BAD) {
bbt_version[block] = 0xFFFFFFFF;
continue;
}
ret = nanddev_read_bbt(nand, start_block + block,
false);
if (ret < 0)
bbt_version[block] = 0xFFFFFFFF;
else if (ret == 0)
bbt_version[block] = 0;
status = snanddev_bbt_get_block_status(nand, start_block + block);
ret = nanddev_read_bbt(nand, start_block + block, false);
if (ret == 0 && status == NAND_BBT_BLOCK_FACTORY_BAD)
bbt_version[block] = BBT_VERSION_INVALID;
else if (ret == -EIO)
bbt_version[block] = BBT_VERSION_INVALID;
else if (ret == BBT_VERSION_BLOCK_ABNORMAL)
bbt_version[block] = ret;
else
bbt_version[block] = ret;
}
get_min_ver:
min_version = 0xFFFFFFFF;
min_version = BBT_VERSION_MAX;
block_des = 0;
for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
if (bbt_version[block] < min_version) {
@@ -338,25 +500,37 @@ get_min_ver:
}
}
/* Overwrite the BBT_VERSION_BLOCK_ABNORMAL block */
if (nand->bbt.version < min_version)
nand->bbt.version = min_version + 4;
if (block_des > 0) {
nand->bbt.version++;
ret = nanddev_write_bbt(nand, block_des);
bbt_version[block_des - start_block] = 0xFFFFFFFF;
if (ret) {
pr_err("%s blk= %d ret= %d\n", __func__,
block_des, ret);
goto get_min_ver;
} else {
count++;
if (count < 2)
goto get_min_ver;
BBT_DBG("%s success\n", __func__);
}
} else {
pr_err("%s failed\n", __func__);
pr_err("bbt_update fail, blk=%d ret= %d\n", block_des, ret);
return -1;
return -1;
}
bbt_version[block_des - start_block] = BBT_VERSION_INVALID;
count++;
if (count < 2)
goto get_min_ver;
BBT_DBG("bbt_update success\n");
} else {
pr_err("bbt_update failed\n");
ret = -1;
}
for (block = 0; block < NANDDEV_BBT_SCAN_MAXBLOCKS; block++) {
if (bbt_version[block] == BBT_VERSION_BLOCK_ABNORMAL) {
block_des = start_block + block;
sfc_nand_erase_mtd(mtd, block_des * mtd->erasesize);
}
}
return ret;
}
#endif
return 0;

View File

@@ -168,6 +168,8 @@ static void md_update_ss_toc(const struct md_region *entry)
shdr->sh_flags = SHF_WRITE;
shdr->sh_offset = minidump_elfheader.elf_offset;
shdr->sh_entsize = 0;
shdr->sh_addralign = shdr->sh_addr; /* backup */
shdr->sh_entsize = entry->phys_addr; /* backup */
if (strstr((const char *)mdr->name, "note"))
phdr->p_type = PT_NOTE;
@@ -178,6 +180,7 @@ static void md_update_ss_toc(const struct md_region *entry)
phdr->p_paddr = entry->phys_addr;
phdr->p_filesz = phdr->p_memsz = mdr->region_size;
phdr->p_flags = PF_R | PF_W;
phdr->p_align = phdr->p_paddr; /* backup */
minidump_elfheader.elf_offset += shdr->sh_size;
mdr->md_valid = MD_REGION_VALID;
minidump_table.md_ss_toc->ss_region_count++;
@@ -274,8 +277,11 @@ int rk_minidump_update_region(int regno, const struct md_region *entry)
phdr = elf_program(hdr, regno + 1);
shdr->sh_addr = (elf_addr_t)entry->virt_addr;
shdr->sh_addralign = shdr->sh_addr; /* backup */
shdr->sh_entsize = entry->phys_addr; /* backup */
phdr->p_vaddr = entry->virt_addr;
phdr->p_paddr = entry->phys_addr;
phdr->p_align = phdr->p_paddr; /* backup */
err_unlock:
read_unlock_irqrestore(&mdt_remove_lock, flags);
@@ -675,6 +681,8 @@ static int rk_minidump_driver_probe(struct platform_device *pdev)
phdr = (Elf64_Phdr *)(md_elf_mem + (ulong)ehdr->e_phoff);
phdr += ehdr->e_phnum - 1;
md_elf_size = phdr->p_memsz + phdr->p_offset;
if (md_elf_size > r_size)
md_elf_size = r_size;
pr_info("Create /proc/rk_md/minidump, size:0x%llx...\n", md_elf_size);
proc_rk_minidump = proc_create("minidump", 0400, base_dir, &rk_minidump_proc_ops);
} else {

View File

@@ -217,6 +217,10 @@ static int ohci_platform_probe(struct platform_device *dev)
device_wakeup_enable(hcd->self.controller);
if (of_device_is_compatible(dev->dev.of_node,
"rockchip,rk3588-ohci"))
device_enable_async_suspend(hcd->self.controller);
platform_set_drvdata(dev, hcd);
return err;

View File

@@ -22,5 +22,7 @@
#define BOOT_UMS (REBOOT_FLAG + 12)
/* reboot system quiescent */
#define BOOT_QUIESCENT (REBOOT_FLAG + 14)
/* reboot by panic and capture ramdump in uboot through usb */
#define BOOT_WINUSB (REBOOT_FLAG + 15)
#endif

View File

@@ -1968,6 +1968,12 @@ struct rkisp_isp2x_luma_buffer {
struct rkisp_mipi_luma luma[ISP2X_MIPI_RAW_MAX];
} __attribute__ ((packed));
enum {
RKISP_RTT_MODE_NORMAL = 0,
RKISP_RTT_MODE_MULTI_FRAME,
RKISP_RTT_MODE_ONE_FRAME,
};
/**
* struct rkisp_thunderboot_resmem_head
*/
@@ -1976,10 +1982,12 @@ struct rkisp_thunderboot_resmem_head {
__u16 complete;
__u16 frm_total;
__u16 hdr_mode;
__u16 rtt_mode;
__u16 width;
__u16 height;
__u16 camera_num;
__u16 camera_index;
__u16 md_flag;
__u32 exp_time[3];
__u32 exp_gain[3];

View File

@@ -52,7 +52,7 @@
#define ISP32_MODULE_CSM ISP3X_MODULE_CSM
#define ISP32_MODULE_CGC ISP3X_MODULE_CGC
#define ISP32_MODULE_VSM BIT_ULL(45)
#define ISP32_MODULE_RTT_FST BIT_ULL(62)
#define ISP32_MODULE_FORCE ISP3X_MODULE_FORCE
/* Measurement types */
@@ -70,6 +70,7 @@
#define ISP32_STAT_DHAZ ISP3X_STAT_DHAZ
#define ISP32_STAT_VSM BIT(18)
#define ISP32_STAT_INFO2DDR BIT(19)
#define ISP32_STAT_RTT_FST BIT(31)
#define ISP32_MESH_BUF_NUM ISP3X_MESH_BUF_NUM