diff --git a/arch/arm/boot/dts/rk3506.dtsi b/arch/arm/boot/dts/rk3506.dtsi index 008580d38ccf..91edbd78f0e0 100644 --- a/arch/arm/boot/dts/rk3506.dtsi +++ b/arch/arm/boot/dts/rk3506.dtsi @@ -1244,6 +1244,13 @@ log_leakage: log-leakage@1f { reg = <0x1f 0x1>; }; + cpu_tsadc_trim_l: cpu-tsadc-trim-l@20 { + reg = <0x20 0x1>; + }; + cpu_tsadc_trim_h: cpu-tsadc-trim-h@21 { + reg = <0x21 0x1>; + bits = <0 2>; + }; }; audio_codec: audio-codec@ff4f8000 { @@ -1352,6 +1359,8 @@ rockchip,hw-tshut-temp = <120000>; rockchip,hw-tshut-mode = <0>; /* tshut mode 0:CRU 1:GPIO */ rockchip,hw-tshut-polarity = <0>; /* tshut polarity 0:LOW 1:HIGH */ + nvmem-cells = <&cpu_tsadc_trim_l>, <&cpu_tsadc_trim_h>; + nvmem-cell-names = "trim_l", "trim_h"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/rk3506g-evb1-v10-mcu-k350c4516t.dts b/arch/arm/boot/dts/rk3506g-evb1-v10-mcu-k350c4516t.dts index 0395310dc5b5..13b444b640b5 100644 --- a/arch/arm/boot/dts/rk3506g-evb1-v10-mcu-k350c4516t.dts +++ b/arch/arm/boot/dts/rk3506g-evb1-v10-mcu-k350c4516t.dts @@ -14,6 +14,10 @@ compatible = "rockchip,rk3506g-evb1-v10-mcu-k350c4516t", "rockchip,rk3506"; }; +&cma { + size = <0x1600000>; +}; + &rgb { status = "okay"; rockchip,data-sync-bypass; @@ -214,6 +218,10 @@ status = "okay"; }; +&u2phy_otg0 { + rockchip,vbus-always-on; +}; + &vop { mcu-timing { mcu-pix-total = <6>; diff --git a/arch/arm/boot/dts/rk3506g-evb1-v10-rgb-Q7050ITH2641AA1T.dts b/arch/arm/boot/dts/rk3506g-evb1-v10-rgb-Q7050ITH2641AA1T.dts index 0e894b1fe598..8a98e6a8ef5f 100644 --- a/arch/arm/boot/dts/rk3506g-evb1-v10-rgb-Q7050ITH2641AA1T.dts +++ b/arch/arm/boot/dts/rk3506g-evb1-v10-rgb-Q7050ITH2641AA1T.dts @@ -52,6 +52,10 @@ }; }; +&cma { + size = <0x1600000>; +}; + &rgb { status = "okay"; pinctrl-names = "default"; @@ -78,3 +82,7 @@ &route_rgb { status = "okay"; }; + +&u2phy_otg0 { + rockchip,vbus-always-on; +}; diff --git a/arch/arm/boot/dts/rk3506g-evb1-v10-sii9022-bt1120-to-hdmi.dts b/arch/arm/boot/dts/rk3506g-evb1-v10-sii9022-bt1120-to-hdmi.dts index 5ac3b9d4e40a..d0a2ac0a27e6 100644 --- a/arch/arm/boot/dts/rk3506g-evb1-v10-sii9022-bt1120-to-hdmi.dts +++ b/arch/arm/boot/dts/rk3506g-evb1-v10-sii9022-bt1120-to-hdmi.dts @@ -14,6 +14,10 @@ compatible = "rockchip,rk3506g-evb1-v10-sii9022-bt1120-to-hdmi", "rockchip,rk3506"; }; +&cma { + size = <0x1600000>; +}; + &i2c2 { clock-frequency = <400000>; pinctrl-names = "default"; @@ -89,3 +93,7 @@ &route_rgb { status = "okay"; }; + +&u2phy_otg0 { + rockchip,vbus-always-on; +}; diff --git a/arch/arm/boot/dts/rk3506g-evb1-v10-sii9022-rgb2hdmi.dts b/arch/arm/boot/dts/rk3506g-evb1-v10-sii9022-rgb2hdmi.dts index 25d2f2ef2e1d..b2969c1987e5 100644 --- a/arch/arm/boot/dts/rk3506g-evb1-v10-sii9022-rgb2hdmi.dts +++ b/arch/arm/boot/dts/rk3506g-evb1-v10-sii9022-rgb2hdmi.dts @@ -14,6 +14,10 @@ compatible = "rockchip,rk3506g-evb1-v10-sii9022-rgb2hdmi", "rockchip,rk3506"; }; +&cma { + size = <0x1600000>; +}; + &i2c2 { clock-frequency = <400000>; pinctrl-0 = <&rm_io4_i2c2_scl &rm_io5_i2c2_sda>; @@ -80,3 +84,7 @@ &route_rgb { status = "okay"; }; + +&u2phy_otg0 { + rockchip,vbus-always-on; +}; diff --git a/arch/arm/boot/dts/rk3506g-iotest-v10.dts b/arch/arm/boot/dts/rk3506g-iotest-v10.dts index cb9f04dee728..73173d3a7714 100644 --- a/arch/arm/boot/dts/rk3506g-iotest-v10.dts +++ b/arch/arm/boot/dts/rk3506g-iotest-v10.dts @@ -203,6 +203,7 @@ }; &u2phy_otg0 { + rockchip,vbus-always-on; status = "okay"; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-ebook-v10.dts b/arch/arm64/boot/dts/rockchip/rk3576-ebook-v10.dts index a61b6b4f3171..569b175d6021 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-ebook-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-ebook-v10.dts @@ -536,6 +536,7 @@ pinctrl-0 = <&sy7636a_default>; enable-gpios = <&gpio3 RK_PA4 GPIO_ACTIVE_HIGH>, <&gpio2 RK_PD1 GPIO_ACTIVE_HIGH>; + pgood-gpio = <&gpio3 RK_PB1 GPIO_ACTIVE_LOW>; thermal-zone = "ebcpmic-thermal"; #thermal-sensor-cells = <0>; @@ -799,7 +800,8 @@ sy7636a_default: sy7636a_default { rockchip,pins = <3 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>, - <2 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>; + <2 RK_PD1 RK_FUNC_GPIO &pcfg_pull_up>, + <3 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-test5-v10.dts b/arch/arm64/boot/dts/rockchip/rk3576-test5-v10.dts index b2eb1d337de5..2ee81e5b4878 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-test5-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rk3576-test5-v10.dts @@ -15,3 +15,19 @@ model = "Rockchip RK3576 TEST5 V10 Board"; compatible = "rockchip,rk3576-test5-v10", "rockchip,rk3576"; }; + +&imx464_0 { + pwdn-gpios = <&gpio3 RK_PC7 GPIO_ACTIVE_HIGH>; +}; + +&imx464_1 { + pwdn-gpios = <&gpio3 RK_PC7 GPIO_ACTIVE_HIGH>; +}; + +&os04a10 { + pwdn-gpios = <&gpio3 RK_PC7 GPIO_ACTIVE_HIGH>; +}; + +&sc4336 { + pwdn-gpios = <&gpio3 RK_PC7 GPIO_ACTIVE_HIGH>; +}; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi index 7e3fe48e4877..88dc57a5b8cc 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576-vehicle-evb-v20-serdes-mfd-display-maxim.dtsi @@ -1640,7 +1640,7 @@ /* dsi->serdes->lvds_panel */ &pwm1_6ch_1 { status = "okay"; - pinctrl-0 = <&pwm1m0_ch1>; + pinctrl-0 = <&pwm1m2_ch1>; }; /* dp->serdes->lvds_panel */ diff --git a/drivers/infiniband/hw/erdma/erdma_hw.h b/drivers/infiniband/hw/erdma/erdma_hw.h index 2eb41e6d94c4..82bf66ca95b7 100644 --- a/drivers/infiniband/hw/erdma/erdma_hw.h +++ b/drivers/infiniband/hw/erdma/erdma_hw.h @@ -11,8 +11,6 @@ #include /* PCIe device related definition. */ -#define PCI_VENDOR_ID_ALIBABA 0x1ded - #define ERDMA_PCI_WIDTH 64 #define ERDMA_FUNC_BAR 0 #define ERDMA_MISX_BAR 2 diff --git a/drivers/media/platform/rockchip/isp/capture.c b/drivers/media/platform/rockchip/isp/capture.c index 82a798b599c0..6dae02bae982 100644 --- a/drivers/media/platform/rockchip/isp/capture.c +++ b/drivers/media/platform/rockchip/isp/capture.c @@ -365,6 +365,108 @@ void rkisp_config_dmatx_valid_buf(struct rkisp_device *dev) } } +void rkisp_stream_vir_cpy_image(struct work_struct *work) +{ + struct rkisp_vir_cpy *cpy = container_of(work, struct rkisp_vir_cpy, work); + struct rkisp_stream *vir = cpy->stream; + struct rkisp_buffer *src_buf = NULL; + struct vb2_buffer *src_vb = NULL; + struct rkisp_device *isp_dev = vir->ispdev; + const struct vb2_mem_ops *g_ops = isp_dev->hw_dev->mem_ops; + void *src = NULL, *dst = NULL, *mem = NULL; + u32 payload_size = 0; + unsigned long lock_flags = 0; + u32 i; + + v4l2_dbg(1, rkisp_debug, &vir->ispdev->v4l2_dev, + "%s enter\n", __func__); + + vir->streaming = true; + spin_lock_irqsave(&vir->vbq_lock, lock_flags); + if (!list_empty(&cpy->queue)) { + src_buf = list_first_entry(&cpy->queue, + struct rkisp_buffer, queue); + list_del(&src_buf->queue); + } + spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); + + while (src_buf || vir->streaming) { + if (vir->stopping || !vir->streaming) + goto end; + + if (!src_buf) + wait_for_completion(&cpy->cmpl); + + vir->frame_end = false; + + spin_lock_irqsave(&vir->vbq_lock, lock_flags); + if (!src_buf && !list_empty(&cpy->queue)) { + src_buf = list_first_entry(&cpy->queue, struct rkisp_buffer, queue); + list_del(&src_buf->queue); + } + + if (src_buf && !vir->curr_buf && !list_empty(&vir->buf_queue)) { + vir->curr_buf = list_first_entry(&vir->buf_queue, + struct rkisp_buffer, queue); + list_del(&vir->curr_buf->queue); + } + spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); + + if (!vir->curr_buf || !src_buf) + goto end; + + src_vb = &src_buf->vb.vb2_buf; + for (i = 0; i < vir->out_isp_fmt.mplanes; i++) { + payload_size = vir->out_fmt.plane_fmt[i].sizeimage; + dst = vb2_plane_vaddr(&vir->curr_buf->vb.vb2_buf, i); + mem = src_vb->planes[i].mem_priv; + src = vb2_plane_vaddr(&src_buf->vb.vb2_buf, i); + + if (!src || !dst) + break; + /* sync cache */ + if (mem) + g_ops->finish(mem); + + vb2_set_plane_payload(&vir->curr_buf->vb.vb2_buf, i, payload_size); + memcpy(dst, src, payload_size); + } + + vir->curr_buf->vb.sequence = src_buf->vb.sequence; + vir->curr_buf->vb.vb2_buf.timestamp = src_buf->vb.vb2_buf.timestamp; + vb2_buffer_done(&vir->curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + vir->curr_buf = NULL; + +end: + if (src_buf) + vb2_buffer_done(&src_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); + src_buf = NULL; + + spin_lock_irqsave(&vir->vbq_lock, lock_flags); + + if (!list_empty(&cpy->queue)) { + src_buf = list_first_entry(&cpy->queue, + struct rkisp_buffer, queue); + list_del(&src_buf->queue); + } else if (vir->stopping) { + vir->streaming = false; + } + + spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); + } + + vir->frame_end = true; + + if (vir->stopping) { + vir->stopping = false; + vir->streaming = false; + wake_up(&vir->done); + } + + v4l2_dbg(1, rkisp_debug, &vir->ispdev->v4l2_dev, + "%s exit\n", __func__); +} + /* Get xsubs and ysubs for fourcc formats * * @xsubs: horizontal color samples in a 4*4 matrix, for yuv @@ -746,6 +848,11 @@ static int rkisp_set_fmt(struct rkisp_stream *stream, t = &dev->cap_dev.stream[i]; if (t->out_isp_fmt.fmt_type != FMT_YUV || !t->streaming) continue; + /* isp v32 v33 mp wrap can't use for iqtool */ + if (i == RKISP_STREAM_MP && + (dev->isp_ver == ISP_V32 || dev->isp_ver == ISP_V33) && + dev->cap_dev.wrap_line) + continue; if (t->out_fmt.plane_fmt[0].sizeimage > imagsize) { imagsize = t->out_fmt.plane_fmt[0].sizeimage; *pixm = t->out_fmt; @@ -1252,6 +1359,13 @@ static int rkisp_set_iqtool_connect_id(struct rkisp_stream *stream, int stream_i goto err; } + if ((dev->isp_ver == ISP_V32 || dev->isp_ver == ISP_V33) && + (stream_id == RKISP_STREAM_MP) && + dev->cap_dev.wrap_line) { + v4l2_err(&dev->v4l2_dev, "isp v32 v33 mp wrap can't use for iqtool"); + goto err; + } + stream->conn_id = stream_id; return 0; err: diff --git a/drivers/media/platform/rockchip/isp/capture.h b/drivers/media/platform/rockchip/isp/capture.h index 4c3d3fc627e9..65b7256fe65e 100644 --- a/drivers/media/platform/rockchip/isp/capture.h +++ b/drivers/media/platform/rockchip/isp/capture.h @@ -345,6 +345,7 @@ extern struct stream_config rkisp_mp_stream_config; extern struct stream_config rkisp_sp_stream_config; extern struct rockit_isp_ops rockit_isp_ops; +void rkisp_stream_vir_cpy_image(struct work_struct *work); void rkisp_stream_buf_done_early(struct rkisp_device *dev); void rkisp_stream_buf_done(struct rkisp_stream *stream, struct rkisp_buffer *buf); diff --git a/drivers/media/platform/rockchip/isp/capture_v21.c b/drivers/media/platform/rockchip/isp/capture_v21.c index e354747e9530..cb394befd7ab 100644 --- a/drivers/media/platform/rockchip/isp/capture_v21.c +++ b/drivers/media/platform/rockchip/isp/capture_v21.c @@ -1404,98 +1404,6 @@ static void rkisp_stream_stop(struct rkisp_stream *stream) stream->interlaced = false; } -static void vir_cpy_image(struct work_struct *work) -{ - struct rkisp_vir_cpy *cpy = - container_of(work, struct rkisp_vir_cpy, work); - struct rkisp_stream *vir = cpy->stream; - struct rkisp_buffer *src_buf = NULL; - unsigned long lock_flags = 0; - u32 i; - - v4l2_dbg(1, rkisp_debug, &vir->ispdev->v4l2_dev, - "%s enter\n", __func__); - - vir->streaming = true; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - if (!list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - - while (src_buf || vir->streaming) { - if (vir->stopping || !vir->streaming) - goto end; - - if (!src_buf) - wait_for_completion(&cpy->cmpl); - - vir->frame_end = false; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - - if (!src_buf && !list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } - - if (src_buf && !vir->curr_buf && !list_empty(&vir->buf_queue)) { - vir->curr_buf = list_first_entry(&vir->buf_queue, - struct rkisp_buffer, queue); - list_del(&vir->curr_buf->queue); - } - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - - if (!vir->curr_buf || !src_buf) - goto end; - - for (i = 0; i < vir->out_isp_fmt.mplanes; i++) { - u32 payload_size = vir->out_fmt.plane_fmt[i].sizeimage; - void *src = vb2_plane_vaddr(&src_buf->vb.vb2_buf, i); - void *dst = vb2_plane_vaddr(&vir->curr_buf->vb.vb2_buf, i); - - if (!src || !dst) - break; - vb2_set_plane_payload(&vir->curr_buf->vb.vb2_buf, i, payload_size); - memcpy(dst, src, payload_size); - } - - vir->curr_buf->vb.sequence = src_buf->vb.sequence; - vir->curr_buf->vb.vb2_buf.timestamp = src_buf->vb.vb2_buf.timestamp; - vb2_buffer_done(&vir->curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - vir->curr_buf = NULL; -end: - if (src_buf) - vb2_buffer_done(&src_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - src_buf = NULL; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - - if (!list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } else if (vir->stopping) { - vir->streaming = false; - } - - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - } - - vir->frame_end = true; - - if (vir->stopping) { - vir->stopping = false; - vir->streaming = false; - wake_up(&vir->done); - } - - v4l2_dbg(1, rkisp_debug, &vir->ispdev->v4l2_dev, - "%s exit\n", __func__); -} - - /* * Most of registers inside rockchip isp1 have shadow register since * they must be not changed during processing a frame. @@ -1793,7 +1701,7 @@ rkisp_start_streaming(struct vb2_queue *queue, unsigned int count) struct rkisp_stream *t = &dev->cap_dev.stream[stream->conn_id]; if (t->streaming) { - INIT_WORK(&dev->cap_dev.vir_cpy.work, vir_cpy_image); + INIT_WORK(&dev->cap_dev.vir_cpy.work, rkisp_stream_vir_cpy_image); init_completion(&dev->cap_dev.vir_cpy.cmpl); INIT_LIST_HEAD(&dev->cap_dev.vir_cpy.queue); dev->cap_dev.vir_cpy.stream = stream; diff --git a/drivers/media/platform/rockchip/isp/capture_v30.c b/drivers/media/platform/rockchip/isp/capture_v30.c index a4acb0eeafe9..532b1de9e8b8 100644 --- a/drivers/media/platform/rockchip/isp/capture_v30.c +++ b/drivers/media/platform/rockchip/isp/capture_v30.c @@ -1305,97 +1305,6 @@ end: mutex_unlock(&dev->hw_dev->dev_lock); } -static void vir_cpy_image(struct work_struct *work) -{ - struct rkisp_vir_cpy *cpy = - container_of(work, struct rkisp_vir_cpy, work); - struct rkisp_stream *vir = cpy->stream; - struct rkisp_buffer *src_buf = NULL; - unsigned long lock_flags = 0; - u32 i; - - v4l2_dbg(1, rkisp_debug, &vir->ispdev->v4l2_dev, - "%s enter\n", __func__); - - vir->streaming = true; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - if (!list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - - while (src_buf || vir->streaming) { - if (vir->stopping || !vir->streaming) - goto end; - - if (!src_buf) - wait_for_completion(&cpy->cmpl); - - vir->frame_end = false; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - - if (!src_buf && !list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } - - if (src_buf && !vir->curr_buf && !list_empty(&vir->buf_queue)) { - vir->curr_buf = list_first_entry(&vir->buf_queue, - struct rkisp_buffer, queue); - list_del(&vir->curr_buf->queue); - } - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - - if (!vir->curr_buf || !src_buf) - goto end; - - for (i = 0; i < vir->out_isp_fmt.mplanes; i++) { - u32 payload_size = vir->out_fmt.plane_fmt[i].sizeimage; - void *src = vb2_plane_vaddr(&src_buf->vb.vb2_buf, i); - void *dst = vb2_plane_vaddr(&vir->curr_buf->vb.vb2_buf, i); - - if (!src || !dst) - break; - vb2_set_plane_payload(&vir->curr_buf->vb.vb2_buf, i, payload_size); - memcpy(dst, src, payload_size); - } - - vir->curr_buf->vb.sequence = src_buf->vb.sequence; - vir->curr_buf->vb.vb2_buf.timestamp = src_buf->vb.vb2_buf.timestamp; - vb2_buffer_done(&vir->curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - vir->curr_buf = NULL; -end: - if (src_buf) - vb2_buffer_done(&src_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - src_buf = NULL; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - - if (!list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } else if (vir->stopping) { - vir->streaming = false; - } - - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - } - - vir->frame_end = true; - - if (vir->stopping) { - vir->stopping = false; - vir->streaming = false; - wake_up(&vir->done); - } - - v4l2_dbg(1, rkisp_debug, &vir->ispdev->v4l2_dev, - "%s exit\n", __func__); -} - static int rkisp_stream_start(struct rkisp_stream *stream) { struct v4l2_device *v4l2_dev = &stream->ispdev->v4l2_dev; @@ -1452,7 +1361,7 @@ rkisp_start_streaming(struct vb2_queue *queue, unsigned int count) struct rkisp_stream *t = &dev->cap_dev.stream[stream->conn_id]; if (t->streaming) { - INIT_WORK(&dev->cap_dev.vir_cpy.work, vir_cpy_image); + INIT_WORK(&dev->cap_dev.vir_cpy.work, rkisp_stream_vir_cpy_image); init_completion(&dev->cap_dev.vir_cpy.cmpl); INIT_LIST_HEAD(&dev->cap_dev.vir_cpy.queue); dev->cap_dev.vir_cpy.stream = stream; diff --git a/drivers/media/platform/rockchip/isp/capture_v32.c b/drivers/media/platform/rockchip/isp/capture_v32.c index ca0186d52d53..db0b1b33e52b 100644 --- a/drivers/media/platform/rockchip/isp/capture_v32.c +++ b/drivers/media/platform/rockchip/isp/capture_v32.c @@ -1943,97 +1943,6 @@ end: } } -static void vir_cpy_image(struct work_struct *work) -{ - struct rkisp_vir_cpy *cpy = - container_of(work, struct rkisp_vir_cpy, work); - struct rkisp_stream *vir = cpy->stream; - struct rkisp_buffer *src_buf = NULL; - unsigned long lock_flags = 0; - u32 i; - - v4l2_dbg(1, rkisp_debug, &vir->ispdev->v4l2_dev, - "%s enter\n", __func__); - - vir->streaming = true; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - if (!list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - - while (src_buf || vir->streaming) { - if (vir->stopping || !vir->streaming) - goto end; - - if (!src_buf) - wait_for_completion(&cpy->cmpl); - - vir->frame_end = false; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - - if (!src_buf && !list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } - - if (src_buf && !vir->curr_buf && !list_empty(&vir->buf_queue)) { - vir->curr_buf = list_first_entry(&vir->buf_queue, - struct rkisp_buffer, queue); - list_del(&vir->curr_buf->queue); - } - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - - if (!vir->curr_buf || !src_buf) - goto end; - - for (i = 0; i < vir->out_isp_fmt.mplanes; i++) { - u32 payload_size = vir->out_fmt.plane_fmt[i].sizeimage; - void *src = vb2_plane_vaddr(&src_buf->vb.vb2_buf, i); - void *dst = vb2_plane_vaddr(&vir->curr_buf->vb.vb2_buf, i); - - if (!src || !dst) - break; - vb2_set_plane_payload(&vir->curr_buf->vb.vb2_buf, i, payload_size); - memcpy(dst, src, payload_size); - } - - vir->curr_buf->vb.sequence = src_buf->vb.sequence; - vir->curr_buf->vb.vb2_buf.timestamp = src_buf->vb.vb2_buf.timestamp; - vb2_buffer_done(&vir->curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - vir->curr_buf = NULL; -end: - if (src_buf) - vb2_buffer_done(&src_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - src_buf = NULL; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - - if (!list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } else if (vir->stopping) { - vir->streaming = false; - } - - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - } - - vir->frame_end = true; - - if (vir->stopping) { - vir->stopping = false; - vir->streaming = false; - wake_up(&vir->done); - } - - v4l2_dbg(1, rkisp_debug, &vir->ispdev->v4l2_dev, - "%s exit\n", __func__); -} - static int rkisp_stream_start(struct rkisp_stream *stream) { struct rkisp_device *dev = stream->ispdev; @@ -2096,7 +2005,7 @@ rkisp_start_streaming(struct vb2_queue *queue, unsigned int count) struct rkisp_stream *t = &dev->cap_dev.stream[stream->conn_id]; if (t->streaming) { - INIT_WORK(&dev->cap_dev.vir_cpy.work, vir_cpy_image); + INIT_WORK(&dev->cap_dev.vir_cpy.work, rkisp_stream_vir_cpy_image); init_completion(&dev->cap_dev.vir_cpy.cmpl); INIT_LIST_HEAD(&dev->cap_dev.vir_cpy.queue); dev->cap_dev.vir_cpy.stream = stream; @@ -2342,11 +2251,14 @@ int rkisp_register_stream_v32(struct rkisp_device *dev) ret = rkisp_stream_init(dev, RKISP_STREAM_SP); if (ret < 0) goto err_free_mp; + ret = rkisp_stream_init(dev, RKISP_STREAM_VIR); + if (ret < 0) + goto err_free_sp; if (dev->isp_ver == ISP_V32) { ret = rkisp_stream_init(dev, RKISP_STREAM_BP); if (ret < 0) - goto err_free_sp; + goto err_free_vir; ret = rkisp_stream_init(dev, RKISP_STREAM_MPDS); if (ret < 0) goto err_free_bp; @@ -2370,6 +2282,8 @@ err_free_mpds: rkisp_unregister_stream_vdev(&cap_dev->stream[RKISP_STREAM_MPDS]); err_free_bp: rkisp_unregister_stream_vdev(&cap_dev->stream[RKISP_STREAM_BP]); +err_free_vir: + rkisp_unregister_stream_vdev(&cap_dev->stream[RKISP_STREAM_VIR]); err_free_sp: rkisp_unregister_stream_vdev(&cap_dev->stream[RKISP_STREAM_SP]); err_free_mp: @@ -2387,6 +2301,8 @@ void rkisp_unregister_stream_v32(struct rkisp_device *dev) rkisp_unregister_stream_vdev(stream); stream = &cap_dev->stream[RKISP_STREAM_SP]; rkisp_unregister_stream_vdev(stream); + stream = &cap_dev->stream[RKISP_STREAM_VIR]; + rkisp_unregister_stream_vdev(stream); if (dev->isp_ver == ISP_V32) { stream = &cap_dev->stream[RKISP_STREAM_BP]; rkisp_unregister_stream_vdev(stream); diff --git a/drivers/media/platform/rockchip/isp/capture_v39.c b/drivers/media/platform/rockchip/isp/capture_v39.c index 1ed0b0a11ac7..e276c77248da 100644 --- a/drivers/media/platform/rockchip/isp/capture_v39.c +++ b/drivers/media/platform/rockchip/isp/capture_v39.c @@ -1387,97 +1387,6 @@ end: mutex_unlock(&dev->hw_dev->dev_lock); } -static void vir_cpy_image(struct work_struct *work) -{ - struct rkisp_vir_cpy *cpy = - container_of(work, struct rkisp_vir_cpy, work); - struct rkisp_stream *vir = cpy->stream; - struct rkisp_buffer *src_buf = NULL; - unsigned long lock_flags = 0; - u32 i; - - v4l2_dbg(1, rkisp_debug, &vir->ispdev->v4l2_dev, - "%s enter\n", __func__); - - vir->streaming = true; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - if (!list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - - while (src_buf || vir->streaming) { - if (vir->stopping || !vir->streaming) - goto end; - - if (!src_buf) - wait_for_completion(&cpy->cmpl); - - vir->frame_end = false; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - - if (!src_buf && !list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } - - if (src_buf && !vir->curr_buf && !list_empty(&vir->buf_queue)) { - vir->curr_buf = list_first_entry(&vir->buf_queue, - struct rkisp_buffer, queue); - list_del(&vir->curr_buf->queue); - } - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - - if (!vir->curr_buf || !src_buf) - goto end; - - for (i = 0; i < vir->out_isp_fmt.mplanes; i++) { - u32 payload_size = vir->out_fmt.plane_fmt[i].sizeimage; - void *src = vb2_plane_vaddr(&src_buf->vb.vb2_buf, i); - void *dst = vb2_plane_vaddr(&vir->curr_buf->vb.vb2_buf, i); - - if (!src || !dst) - break; - vb2_set_plane_payload(&vir->curr_buf->vb.vb2_buf, i, payload_size); - memcpy(dst, src, payload_size); - } - - vir->curr_buf->vb.sequence = src_buf->vb.sequence; - vir->curr_buf->vb.vb2_buf.timestamp = src_buf->vb.vb2_buf.timestamp; - vb2_buffer_done(&vir->curr_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - vir->curr_buf = NULL; -end: - if (src_buf) - vb2_buffer_done(&src_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); - src_buf = NULL; - spin_lock_irqsave(&vir->vbq_lock, lock_flags); - - if (!list_empty(&cpy->queue)) { - src_buf = list_first_entry(&cpy->queue, - struct rkisp_buffer, queue); - list_del(&src_buf->queue); - } else if (vir->stopping) { - vir->streaming = false; - } - - spin_unlock_irqrestore(&vir->vbq_lock, lock_flags); - } - - vir->frame_end = true; - - if (vir->stopping) { - vir->stopping = false; - vir->streaming = false; - wake_up(&vir->done); - } - - v4l2_dbg(1, rkisp_debug, &vir->ispdev->v4l2_dev, - "%s exit\n", __func__); -} - static int rkisp_stream_start(struct rkisp_stream *stream) { struct rkisp_device *dev = stream->ispdev; @@ -1536,7 +1445,7 @@ rkisp_start_streaming(struct vb2_queue *queue, unsigned int count) struct rkisp_stream *t = &dev->cap_dev.stream[stream->conn_id]; if (t->streaming) { - INIT_WORK(&dev->cap_dev.vir_cpy.work, vir_cpy_image); + INIT_WORK(&dev->cap_dev.vir_cpy.work, rkisp_stream_vir_cpy_image); init_completion(&dev->cap_dev.vir_cpy.cmpl); INIT_LIST_HEAD(&dev->cap_dev.vir_cpy.queue); dev->cap_dev.vir_cpy.stream = stream; diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c index ff457ea17130..ab94a95e615d 100755 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie.c @@ -108,6 +108,10 @@ #endif /* DHD_CONTROL_PCIE_CPUCORE_WIFI_TURNON */ #include +#ifdef CONFIG_ARCH_ROCKCHIP +#include +#endif + #define EXTENDED_PCIE_DEBUG_DUMP 1 /* Enable Extended pcie registers dump */ #define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ @@ -7920,6 +7924,17 @@ dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) DHD_ERROR(("%s: == Power ON ==\n", __FUNCTION__)); /* PCIe RC Turn on */ do { +#ifdef CONFIG_ARCH_ROCKCHIP + if (bus->rc_dev) { + bcmerror = rockchip_dw_pcie_pm_ctrl_for_user(bus->rc_dev, ROCKCHIP_PCIE_PM_CTRL_RESET); + if (bcmerror) { + DHD_ERROR(("%s Failed to bring up PCIe link\n", __FUNCTION__)); + OSL_SLEEP(10); + continue; + } + + } +#endif /* CONFIG_ARCH_ROCKCHIP */ bcmerror = dhdpcie_bus_start_host_dev(bus); if (!bcmerror) { DHD_ERROR_MEM(("%s: dhdpcie_bus_start_host_dev OK\n", diff --git a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c index 832bf23844ac..0daa1e6e38f8 100755 --- a/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c +++ b/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_pcie_linux.c @@ -2403,11 +2403,6 @@ dhdpcie_start_host_dev(dhd_bus_t *bus) ret = msm_pcie_pm_control(MSM_PCIE_RESUME, bus->dev->bus->number, bus->dev, NULL, 0); #endif /* CONFIG_ARCH_MSM */ -#ifdef CONFIG_ARCH_ROCKCHIP - if (bus->rc_dev) - ret = rockchip_dw_pcie_pm_ctrl_for_user(bus->rc_dev, ROCKCHIP_PCIE_PM_CTRL_RESET); -#endif /* CONFIG_ARCH_ROCKCHIP */ - if (ret) { DHD_ERROR(("%s Failed to bring up PCIe link\n", __FUNCTION__)); goto done; diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 708c7529647f..e071551ed757 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -580,3 +580,15 @@ int pci_write_config_dword(const struct pci_dev *dev, int where, return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val); } EXPORT_SYMBOL(pci_write_config_dword); + +void pci_clear_and_set_config_dword(const struct pci_dev *dev, int pos, + u32 clear, u32 set) +{ + u32 val; + + pci_read_config_dword(dev, pos, &val); + val &= ~clear; + val |= set; + pci_write_config_dword(dev, pos, val); +} +EXPORT_SYMBOL(pci_clear_and_set_config_dword); diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 7948cd11e2de..a9f528f1d842 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -92,6 +92,7 @@ config PCIE_DW_ROCKCHIP config PCIE_RK_THREADED_INIT bool "Threaded initialize Rockchip DW based PCIe controller" depends on PCIE_DW_ROCKCHIP + depends on !DWC_PCIE_PMU default y help Enables threaded initialize Rockchip DW based PCIe controller. diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index 8b9b13e812a2..d8f4a3c2c811 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -143,6 +143,7 @@ struct rk_pcie { raw_spinlock_t intx_lock; u16 aspm; u32 l1ss_ctl1; + u32 l1ss_ctl2; struct dentry *debugfs; u32 msi_vector_num; struct workqueue_struct *hot_rst_wq; @@ -303,6 +304,34 @@ static int rk_pcie_disable_power(struct rk_pcie *rk_pcie) return ret; } +static void rk_pcie_retrain(struct dw_pcie *pci) +{ + u32 pcie_cap_off; + u16 lnk_stat, lnk_ctl; + int ret; + + /* + * Set retrain bit if current speed is 2.5 GB/s, + * but the PCIe root port support is > 2.5 GB/s. + */ + if (pci->link_gen < 2) + return; + + dev_info(pci->dev, "Retrain link..\n"); + pcie_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + lnk_stat = dw_pcie_readw_dbi(pci, pcie_cap_off + PCI_EXP_LNKSTA); + if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) { + lnk_ctl = dw_pcie_readw_dbi(pci, pcie_cap_off + PCI_EXP_LNKCTL); + lnk_ctl |= PCI_EXP_LNKCTL_RL; + dw_pcie_writew_dbi(pci, pcie_cap_off + PCI_EXP_LNKCTL, lnk_ctl); + + ret = readw_poll_timeout(pci->dbi_base + pcie_cap_off + PCI_EXP_LNKSTA, + lnk_stat, ((lnk_stat & PCI_EXP_LNKSTA_LT) == 0), 1000, HZ); + if (ret) + dev_err(pci->dev, "Retrain link timeout\n"); + } +} + static int rk_pcie_establish_link(struct dw_pcie *pci) { int retries, power; @@ -1312,6 +1341,8 @@ static int rk_pcie_really_probe(void *p) if (ret) goto release_driver; + reset_control_assert(rk_pcie->rsts); + udelay(10); reset_control_deassert(rk_pcie->rsts); ret = clk_bulk_prepare_enable(rk_pcie->clk_cnt, rk_pcie->clks); @@ -1434,46 +1465,69 @@ static void rk_pcie_downstream_dev_to_d0(struct rk_pcie *rk_pcie, bool enable) } /* Save and restore root bus ASPM */ - if (enable) { - if (rk_pcie->l1ss_ctl1) - dw_pcie_writel_dbi(rk_pcie->pci, bridge->l1ss + PCI_L1SS_CTL1, rk_pcie->l1ss_ctl1); - - /* rk_pcie->aspm woule be saved in advance when enable is false */ - dw_pcie_writel_dbi(rk_pcie->pci, bridge->pcie_cap + PCI_EXP_LNKCTL, rk_pcie->aspm); - } else { + if (!enable) { val = dw_pcie_readl_dbi(rk_pcie->pci, bridge->l1ss + PCI_L1SS_CTL1); - if (val & PCI_L1SS_CTL1_L1SS_MASK) + if (val & PCI_L1SS_CTL1_L1SS_MASK) { rk_pcie->l1ss_ctl1 = val; - else + rk_pcie->l1ss_ctl2 = dw_pcie_readl_dbi(rk_pcie->pci, + bridge->l1ss + PCI_L1SS_CTL2); + } else { rk_pcie->l1ss_ctl1 = 0; + rk_pcie->l1ss_ctl2 = 0; + } val = dw_pcie_readl_dbi(rk_pcie->pci, bridge->pcie_cap + PCI_EXP_LNKCTL); rk_pcie->aspm = val & PCI_EXP_LNKCTL_ASPMC; - val &= ~(PCI_EXP_LNKCAP_ASPM_L1 | PCI_EXP_LNKCAP_ASPM_L0S); - dw_pcie_writel_dbi(rk_pcie->pci, bridge->pcie_cap + PCI_EXP_LNKCTL, val); } + if (enable) { + if (rk_pcie->l1ss_ctl1) { + dw_pcie_writel_dbi(rk_pcie->pci, bridge->l1ss + PCI_L1SS_CTL2, + rk_pcie->l1ss_ctl2); + dw_pcie_writel_dbi(rk_pcie->pci, bridge->l1ss + PCI_L1SS_CTL1, + rk_pcie->l1ss_ctl1); + if (bridge->ltr_path) + pcie_capability_set_word(bridge, PCI_EXP_DEVCTL2, 0x0400); + } + } + + if (enable) { + list_for_each_entry(pdev, &root_bus->devices, bus_list) { + if (PCI_SLOT(pdev->devfn) == 0) { + if (rk_pcie->l1ss_ctl1) { + pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL2, + rk_pcie->l1ss_ctl2); + pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1, + rk_pcie->l1ss_ctl1); + } + } + } + } + + if (enable) + dw_pcie_writel_dbi(rk_pcie->pci, bridge->pcie_cap + PCI_EXP_LNKCTL, rk_pcie->aspm); + list_for_each_entry(pdev, &root_bus->devices, bus_list) { if (PCI_SLOT(pdev->devfn) == 0) { if (pci_set_power_state(pdev, PCI_D0)) dev_err(rk_pcie->pci->dev, - "Failed to transition %s to D3hot state\n", + "Failed to transition %s to D0 state\n", dev_name(&pdev->dev)); - if (enable) { - if (rk_pcie->l1ss_ctl1) { - pci_read_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1, &val); - val &= ~PCI_L1SS_CTL1_L1SS_MASK; - val |= (rk_pcie->l1ss_ctl1 & PCI_L1SS_CTL1_L1SS_MASK); - pci_write_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1, val); - } - + if (enable) pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL, - PCI_EXP_LNKCTL_ASPMC, rk_pcie->aspm); - } else { - pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); - } + PCI_EXP_LNKCTL_ASPMC, + rk_pcie->aspm); + else + pci_disable_link_state(pdev, + PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1); } } + + if (!enable) { + val = dw_pcie_readl_dbi(rk_pcie->pci, bridge->pcie_cap + PCI_EXP_LNKCTL); + val &= ~(PCI_EXP_LNKCTL_ASPM_L1 | PCI_EXP_LNKCTL_ASPM_L0S); + dw_pcie_writel_dbi(rk_pcie->pci, bridge->pcie_cap + PCI_EXP_LNKCTL, val); + } } #endif @@ -1658,6 +1712,9 @@ int rockchip_dw_pcie_pm_ctrl_for_user(struct pci_dev *dev, enum rockchip_pcie_pm rockchip_dw_pcie_suspend(rk_pcie->pci->dev); rockchip_dw_pcie_resume(rk_pcie->pci->dev); break; + case ROCKCHIP_PCIE_PM_RETRAIN_LINK: + rk_pcie_retrain(pci); + break; default: dev_err(rk_pcie->pci->dev, "%s flag=%d invalid\n", __func__, flag); return -EINVAL; diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 25736d408e88..9ba639f352e6 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -474,17 +474,6 @@ static void pcie_aspm_check_latency(struct pci_dev *endpoint) } } -static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos, - u32 clear, u32 set) -{ - u32 val; - - pci_read_config_dword(pdev, pos, &val); - val &= ~clear; - val |= set; - pci_write_config_dword(pdev, pos, val); -} - /* Calculate L1.2 PM substate timing parameters */ static void aspm_calc_l1ss_info(struct pcie_link_state *link, u32 parent_l1ss_cap, u32 child_l1ss_cap) @@ -548,10 +537,12 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link, cl1_2_enables = cctl1 & PCI_L1SS_CTL1_L1_2_MASK; if (pl1_2_enables || cl1_2_enables) { - pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, - PCI_L1SS_CTL1_L1_2_MASK, 0); - pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, - PCI_L1SS_CTL1_L1_2_MASK, 0); + pci_clear_and_set_config_dword(child, + child->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_L1_2_MASK, 0); + pci_clear_and_set_config_dword(parent, + parent->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_L1_2_MASK, 0); } /* Program T_POWER_ON times in both ports */ @@ -559,22 +550,26 @@ static void aspm_calc_l1ss_info(struct pcie_link_state *link, pci_write_config_dword(child, child->l1ss + PCI_L1SS_CTL2, ctl2); /* Program Common_Mode_Restore_Time in upstream device */ - pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, - PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1); + pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_CM_RESTORE_TIME, ctl1); /* Program LTR_L1.2_THRESHOLD time in both ports */ - pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, - PCI_L1SS_CTL1_LTR_L12_TH_VALUE | - PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1); - pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, - PCI_L1SS_CTL1_LTR_L12_TH_VALUE | - PCI_L1SS_CTL1_LTR_L12_TH_SCALE, ctl1); + pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_LTR_L12_TH_VALUE | + PCI_L1SS_CTL1_LTR_L12_TH_SCALE, + ctl1); + pci_clear_and_set_config_dword(child, child->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_LTR_L12_TH_VALUE | + PCI_L1SS_CTL1_LTR_L12_TH_SCALE, + ctl1); if (pl1_2_enables || cl1_2_enables) { - pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, 0, - pl1_2_enables); - pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, 0, - cl1_2_enables); + pci_clear_and_set_config_dword(parent, + parent->l1ss + PCI_L1SS_CTL1, 0, + pl1_2_enables); + pci_clear_and_set_config_dword(child, + child->l1ss + PCI_L1SS_CTL1, 0, + cl1_2_enables); } } @@ -734,10 +729,10 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state) */ /* Disable all L1 substates */ - pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, - PCI_L1SS_CTL1_L1SS_MASK, 0); - pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, - PCI_L1SS_CTL1_L1SS_MASK, 0); + pci_clear_and_set_config_dword(child, child->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_L1SS_MASK, 0); + pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_L1SS_MASK, 0); /* * If needed, disable L1, and it gets enabled later * in pcie_config_aspm_link(). @@ -760,10 +755,10 @@ static void pcie_config_aspm_l1ss(struct pcie_link_state *link, u32 state) val |= PCI_L1SS_CTL1_PCIPM_L1_2; /* Enable what we need to enable */ - pci_clear_and_set_dword(parent, parent->l1ss + PCI_L1SS_CTL1, - PCI_L1SS_CTL1_L1SS_MASK, val); - pci_clear_and_set_dword(child, child->l1ss + PCI_L1SS_CTL1, - PCI_L1SS_CTL1_L1SS_MASK, val); + pci_clear_and_set_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_L1SS_MASK, val); + pci_clear_and_set_config_dword(child, child->l1ss + PCI_L1SS_CTL1, + PCI_L1SS_CTL1_L1SS_MASK, val); } static void pcie_config_aspm_dev(struct pci_dev *pdev, u32 val) diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig index 2cfd196ea597..bd5f723b048e 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -209,4 +209,11 @@ config MARVELL_CN10K_DDR_PMU Enable perf support for Marvell DDR Performance monitoring event on CN10K platform. +config DWC_PCIE_PMU + tristate "Synopsys DesignWare PCIe PMU" + depends on PCI + help + Enable perf support for Synopsys DesignWare PCIe PMU Performance + monitoring event on platform including the Alibaba Yitian 710. + endmenu diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile index 27804e603e7b..06c517c506d9 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_MARVELL_CN10K_TAD_PMU) += marvell_cn10k_tad_pmu.o obj-$(CONFIG_MARVELL_CN10K_DDR_PMU) += marvell_cn10k_ddr_pmu.o obj-$(CONFIG_APPLE_M1_CPU_PMU) += apple_m1_cpu_pmu.o obj-$(CONFIG_ALIBABA_UNCORE_DRW_PMU) += alibaba_uncore_drw_pmu.o +obj-$(CONFIG_DWC_PCIE_PMU) += dwc_pcie_pmu.o diff --git a/drivers/perf/dwc_pcie_pmu.c b/drivers/perf/dwc_pcie_pmu.c new file mode 100644 index 000000000000..c0b8822e87bd --- /dev/null +++ b/drivers/perf/dwc_pcie_pmu.c @@ -0,0 +1,792 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Synopsys DesignWare PCIe PMU driver + * + * Copyright (C) 2021-2023 Alibaba Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DWC_PCIE_VSEC_RAS_DES_ID 0x02 +#define DWC_PCIE_EVENT_CNT_CTL 0x8 + +/* + * Event Counter Data Select includes two parts: + * - 27-24: Group number(4-bit: 0..0x7) + * - 23-16: Event number(8-bit: 0..0x13) within the Group + * + * Put them together as in TRM. + */ +#define DWC_PCIE_CNT_EVENT_SEL GENMASK(27, 16) +#define DWC_PCIE_CNT_LANE_SEL GENMASK(11, 8) +#define DWC_PCIE_CNT_STATUS BIT(7) +#define DWC_PCIE_CNT_ENABLE GENMASK(4, 2) +#define DWC_PCIE_PER_EVENT_OFF 0x1 +#define DWC_PCIE_PER_EVENT_ON 0x3 +#define DWC_PCIE_EVENT_CLEAR GENMASK(1, 0) +#define DWC_PCIE_EVENT_PER_CLEAR 0x1 + +#define DWC_PCIE_EVENT_CNT_DATA 0xC + +#define DWC_PCIE_TIME_BASED_ANAL_CTL 0x10 +#define DWC_PCIE_TIME_BASED_REPORT_SEL GENMASK(31, 24) +#define DWC_PCIE_TIME_BASED_DURATION_SEL GENMASK(15, 8) +#define DWC_PCIE_DURATION_MANUAL_CTL 0x0 +#define DWC_PCIE_DURATION_1MS 0x1 +#define DWC_PCIE_DURATION_10MS 0x2 +#define DWC_PCIE_DURATION_100MS 0x3 +#define DWC_PCIE_DURATION_1S 0x4 +#define DWC_PCIE_DURATION_2S 0x5 +#define DWC_PCIE_DURATION_4S 0x6 +#define DWC_PCIE_DURATION_4US 0xFF +#define DWC_PCIE_TIME_BASED_TIMER_START BIT(0) +#define DWC_PCIE_TIME_BASED_CNT_ENABLE 0x1 + +#define DWC_PCIE_TIME_BASED_ANAL_DATA_REG_LOW 0x14 +#define DWC_PCIE_TIME_BASED_ANAL_DATA_REG_HIGH 0x18 + +/* Event attributes */ +#define DWC_PCIE_CONFIG_EVENTID GENMASK(15, 0) +#define DWC_PCIE_CONFIG_TYPE GENMASK(19, 16) +#define DWC_PCIE_CONFIG_LANE GENMASK(27, 20) + +#define DWC_PCIE_EVENT_ID(event) FIELD_GET(DWC_PCIE_CONFIG_EVENTID, (event)->attr.config) +#define DWC_PCIE_EVENT_TYPE(event) FIELD_GET(DWC_PCIE_CONFIG_TYPE, (event)->attr.config) +#define DWC_PCIE_EVENT_LANE(event) FIELD_GET(DWC_PCIE_CONFIG_LANE, (event)->attr.config) + +enum dwc_pcie_event_type { + DWC_PCIE_TIME_BASE_EVENT, + DWC_PCIE_LANE_EVENT, + DWC_PCIE_EVENT_TYPE_MAX, +}; + +#define DWC_PCIE_LANE_EVENT_MAX_PERIOD GENMASK_ULL(31, 0) +#define DWC_PCIE_MAX_PERIOD GENMASK_ULL(63, 0) + +struct dwc_pcie_pmu { + struct pmu pmu; + struct pci_dev *pdev; /* Root Port device */ + u16 ras_des_offset; + u32 nr_lanes; + + struct list_head pmu_node; + struct hlist_node cpuhp_node; + struct perf_event *event[DWC_PCIE_EVENT_TYPE_MAX]; + int on_cpu; +}; + +#define to_dwc_pcie_pmu(p) (container_of(p, struct dwc_pcie_pmu, pmu)) + +static int dwc_pcie_pmu_hp_state; +static struct list_head dwc_pcie_dev_info_head = + LIST_HEAD_INIT(dwc_pcie_dev_info_head); +static bool notify; + +struct dwc_pcie_dev_info { + struct platform_device *plat_dev; + struct pci_dev *pdev; + struct list_head dev_node; +}; + +struct dwc_pcie_vendor_id { + int vendor_id; +}; + +static const struct dwc_pcie_vendor_id dwc_pcie_vendor_ids[] = { + {.vendor_id = PCI_VENDOR_ID_ALIBABA }, + {.vendor_id = PCI_VENDOR_ID_ROCKCHIP }, + {} /* terminator */ +}; + +static ssize_t cpumask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct dwc_pcie_pmu *pcie_pmu = to_dwc_pcie_pmu(dev_get_drvdata(dev)); + + return cpumap_print_to_pagebuf(true, buf, cpumask_of(pcie_pmu->on_cpu)); +} +static DEVICE_ATTR_RO(cpumask); + +static struct attribute *dwc_pcie_pmu_cpumask_attrs[] = { + &dev_attr_cpumask.attr, + NULL +}; + +static struct attribute_group dwc_pcie_cpumask_attr_group = { + .attrs = dwc_pcie_pmu_cpumask_attrs, +}; + +struct dwc_pcie_format_attr { + struct device_attribute attr; + u64 field; + int config; +}; + +PMU_FORMAT_ATTR(eventid, "config:0-15"); +PMU_FORMAT_ATTR(type, "config:16-19"); +PMU_FORMAT_ATTR(lane, "config:20-27"); + +static struct attribute *dwc_pcie_format_attrs[] = { + &format_attr_type.attr, + &format_attr_eventid.attr, + &format_attr_lane.attr, + NULL, +}; + +static struct attribute_group dwc_pcie_format_attrs_group = { + .name = "format", + .attrs = dwc_pcie_format_attrs, +}; + +struct dwc_pcie_event_attr { + struct device_attribute attr; + enum dwc_pcie_event_type type; + u16 eventid; + u8 lane; +}; + +static ssize_t dwc_pcie_event_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dwc_pcie_event_attr *eattr; + + eattr = container_of(attr, typeof(*eattr), attr); + + if (eattr->type == DWC_PCIE_LANE_EVENT) + return sysfs_emit(buf, "eventid=0x%x,type=0x%x,lane=?\n", + eattr->eventid, eattr->type); + else if (eattr->type == DWC_PCIE_TIME_BASE_EVENT) + return sysfs_emit(buf, "eventid=0x%x,type=0x%x\n", + eattr->eventid, eattr->type); + + return 0; +} + +#define DWC_PCIE_EVENT_ATTR(_name, _type, _eventid, _lane) \ + (&((struct dwc_pcie_event_attr[]) {{ \ + .attr = __ATTR(_name, 0444, dwc_pcie_event_show, NULL), \ + .type = _type, \ + .eventid = _eventid, \ + .lane = _lane, \ + }})[0].attr.attr) + +#define DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(_name, _eventid) \ + DWC_PCIE_EVENT_ATTR(_name, DWC_PCIE_TIME_BASE_EVENT, _eventid, 0) +#define DWC_PCIE_PMU_LANE_EVENT_ATTR(_name, _eventid) \ + DWC_PCIE_EVENT_ATTR(_name, DWC_PCIE_LANE_EVENT, _eventid, 0) + +static struct attribute *dwc_pcie_pmu_time_event_attrs[] = { + /* Group #0 */ + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(one_cycle, 0x00), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(TX_L0S, 0x01), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(RX_L0S, 0x02), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(L0, 0x03), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(L1, 0x04), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(L1_1, 0x05), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(L1_2, 0x06), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(CFG_RCVRY, 0x07), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(TX_RX_L0S, 0x08), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(L1_AUX, 0x09), + + /* Group #1 */ + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(Tx_PCIe_TLP_Data_Payload, 0x20), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(Rx_PCIe_TLP_Data_Payload, 0x21), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(Tx_CCIX_TLP_Data_Payload, 0x22), + DWC_PCIE_PMU_TIME_BASE_EVENT_ATTR(Rx_CCIX_TLP_Data_Payload, 0x23), + + /* + * Leave it to the user to specify the lane ID to avoid generating + * a list of hundreds of events. + */ + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_ack_dllp, 0x600), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_update_fc_dllp, 0x601), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_ack_dllp, 0x602), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_update_fc_dllp, 0x603), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_nulified_tlp, 0x604), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_nulified_tlp, 0x605), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_duplicate_tl, 0x606), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_memory_write, 0x700), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_memory_read, 0x701), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_configuration_write, 0x702), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_configuration_read, 0x703), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_io_write, 0x704), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_io_read, 0x705), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_completion_without_data, 0x706), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_completion_with_data, 0x707), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_message_tlp, 0x708), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_atomic, 0x709), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_tlp_with_prefix, 0x70A), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_memory_write, 0x70B), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_memory_read, 0x70C), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_io_write, 0x70F), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_io_read, 0x710), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_completion_without_data, 0x711), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_completion_with_data, 0x712), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_message_tlp, 0x713), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_atomic, 0x714), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_tlp_with_prefix, 0x715), + DWC_PCIE_PMU_LANE_EVENT_ATTR(tx_ccix_tlp, 0x716), + DWC_PCIE_PMU_LANE_EVENT_ATTR(rx_ccix_tlp, 0x717), + NULL +}; + +static const struct attribute_group dwc_pcie_event_attrs_group = { + .name = "events", + .attrs = dwc_pcie_pmu_time_event_attrs, +}; + +static const struct attribute_group *dwc_pcie_attr_groups[] = { + &dwc_pcie_event_attrs_group, + &dwc_pcie_format_attrs_group, + &dwc_pcie_cpumask_attr_group, + NULL +}; + +static void dwc_pcie_pmu_lane_event_enable(struct dwc_pcie_pmu *pcie_pmu, + bool enable) +{ + struct pci_dev *pdev = pcie_pmu->pdev; + u16 ras_des_offset = pcie_pmu->ras_des_offset; + + if (enable) + pci_clear_and_set_config_dword(pdev, + ras_des_offset + DWC_PCIE_EVENT_CNT_CTL, + DWC_PCIE_CNT_ENABLE, DWC_PCIE_PER_EVENT_ON); + else + pci_clear_and_set_config_dword(pdev, + ras_des_offset + DWC_PCIE_EVENT_CNT_CTL, + DWC_PCIE_CNT_ENABLE, DWC_PCIE_PER_EVENT_OFF); +} + +static void dwc_pcie_pmu_time_based_event_enable(struct dwc_pcie_pmu *pcie_pmu, + bool enable) +{ + struct pci_dev *pdev = pcie_pmu->pdev; + u16 ras_des_offset = pcie_pmu->ras_des_offset; + + pci_clear_and_set_config_dword(pdev, + ras_des_offset + DWC_PCIE_TIME_BASED_ANAL_CTL, + DWC_PCIE_TIME_BASED_TIMER_START, enable); +} + +static u64 dwc_pcie_pmu_read_lane_event_counter(struct perf_event *event) +{ + struct dwc_pcie_pmu *pcie_pmu = to_dwc_pcie_pmu(event->pmu); + struct pci_dev *pdev = pcie_pmu->pdev; + u16 ras_des_offset = pcie_pmu->ras_des_offset; + u32 val; + + pci_read_config_dword(pdev, ras_des_offset + DWC_PCIE_EVENT_CNT_DATA, &val); + + return val; +} + +static u64 dwc_pcie_pmu_read_time_based_counter(struct perf_event *event) +{ + struct dwc_pcie_pmu *pcie_pmu = to_dwc_pcie_pmu(event->pmu); + struct pci_dev *pdev = pcie_pmu->pdev; + int event_id = DWC_PCIE_EVENT_ID(event); + u16 ras_des_offset = pcie_pmu->ras_des_offset; + u32 lo, hi, ss; + u64 val; + + /* + * The 64-bit value of the data counter is spread across two + * registers that are not synchronized. In order to read them + * atomically, ensure that the high 32 bits match before and after + * reading the low 32 bits. + */ + pci_read_config_dword(pdev, + ras_des_offset + DWC_PCIE_TIME_BASED_ANAL_DATA_REG_HIGH, &hi); + do { + /* snapshot the high 32 bits */ + ss = hi; + + pci_read_config_dword( + pdev, ras_des_offset + DWC_PCIE_TIME_BASED_ANAL_DATA_REG_LOW, + &lo); + pci_read_config_dword( + pdev, ras_des_offset + DWC_PCIE_TIME_BASED_ANAL_DATA_REG_HIGH, + &hi); + } while (hi != ss); + + val = ((u64)hi << 32) | lo; + /* + * The Group#1 event measures the amount of data processed in 16-byte + * units. Simplify the end-user interface by multiplying the counter + * at the point of read. + */ + if (event_id >= 0x20 && event_id <= 0x23) + val *= 16; + + return val; +} + +static void dwc_pcie_pmu_event_update(struct perf_event *event) +{ + struct hw_perf_event *hwc = &event->hw; + enum dwc_pcie_event_type type = DWC_PCIE_EVENT_TYPE(event); + u64 delta, prev, now = 0; + + do { + prev = local64_read(&hwc->prev_count); + + if (type == DWC_PCIE_LANE_EVENT) + now = dwc_pcie_pmu_read_lane_event_counter(event); + else if (type == DWC_PCIE_TIME_BASE_EVENT) + now = dwc_pcie_pmu_read_time_based_counter(event); + + } while (local64_cmpxchg(&hwc->prev_count, prev, now) != prev); + + delta = (now - prev) & DWC_PCIE_MAX_PERIOD; + /* 32-bit counter for Lane Event Counting */ + if (type == DWC_PCIE_LANE_EVENT) + delta &= DWC_PCIE_LANE_EVENT_MAX_PERIOD; + + local64_add(delta, &event->count); +} + +static int dwc_pcie_pmu_event_init(struct perf_event *event) +{ + struct dwc_pcie_pmu *pcie_pmu = to_dwc_pcie_pmu(event->pmu); + enum dwc_pcie_event_type type = DWC_PCIE_EVENT_TYPE(event); + struct perf_event *sibling; + u32 lane; + + if (event->attr.type != event->pmu->type) + return -ENOENT; + + /* We don't support sampling */ + if (is_sampling_event(event)) + return -EINVAL; + + /* We cannot support task bound events */ + if (event->cpu < 0 || event->attach_state & PERF_ATTACH_TASK) + return -EINVAL; + + if (event->group_leader != event && + !is_software_event(event->group_leader)) + return -EINVAL; + + for_each_sibling_event(sibling, event->group_leader) { + if (sibling->pmu != event->pmu && !is_software_event(sibling)) + return -EINVAL; + } + + if (type < 0 || type >= DWC_PCIE_EVENT_TYPE_MAX) + return -EINVAL; + + if (type == DWC_PCIE_LANE_EVENT) { + lane = DWC_PCIE_EVENT_LANE(event); + if (lane < 0 || lane >= pcie_pmu->nr_lanes) + return -EINVAL; + } + + event->cpu = pcie_pmu->on_cpu; + + return 0; +} + +static void dwc_pcie_pmu_event_start(struct perf_event *event, int flags) +{ + struct hw_perf_event *hwc = &event->hw; + struct dwc_pcie_pmu *pcie_pmu = to_dwc_pcie_pmu(event->pmu); + enum dwc_pcie_event_type type = DWC_PCIE_EVENT_TYPE(event); + + hwc->state = 0; + local64_set(&hwc->prev_count, 0); + + if (type == DWC_PCIE_LANE_EVENT) + dwc_pcie_pmu_lane_event_enable(pcie_pmu, true); + else if (type == DWC_PCIE_TIME_BASE_EVENT) + dwc_pcie_pmu_time_based_event_enable(pcie_pmu, true); +} + +static void dwc_pcie_pmu_event_stop(struct perf_event *event, int flags) +{ + struct dwc_pcie_pmu *pcie_pmu = to_dwc_pcie_pmu(event->pmu); + enum dwc_pcie_event_type type = DWC_PCIE_EVENT_TYPE(event); + struct hw_perf_event *hwc = &event->hw; + + if (event->hw.state & PERF_HES_STOPPED) + return; + + if (type == DWC_PCIE_LANE_EVENT) + dwc_pcie_pmu_lane_event_enable(pcie_pmu, false); + else if (type == DWC_PCIE_TIME_BASE_EVENT) + dwc_pcie_pmu_time_based_event_enable(pcie_pmu, false); + + dwc_pcie_pmu_event_update(event); + hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; +} + +static int dwc_pcie_pmu_event_add(struct perf_event *event, int flags) +{ + struct dwc_pcie_pmu *pcie_pmu = to_dwc_pcie_pmu(event->pmu); + struct pci_dev *pdev = pcie_pmu->pdev; + struct hw_perf_event *hwc = &event->hw; + enum dwc_pcie_event_type type = DWC_PCIE_EVENT_TYPE(event); + int event_id = DWC_PCIE_EVENT_ID(event); + int lane = DWC_PCIE_EVENT_LANE(event); + u16 ras_des_offset = pcie_pmu->ras_des_offset; + u32 ctrl; + + /* one counter for each type and it is in use */ + if (pcie_pmu->event[type]) + return -ENOSPC; + + pcie_pmu->event[type] = event; + hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; + + if (type == DWC_PCIE_LANE_EVENT) { + /* EVENT_COUNTER_DATA_REG needs clear manually */ + ctrl = FIELD_PREP(DWC_PCIE_CNT_EVENT_SEL, event_id) | + FIELD_PREP(DWC_PCIE_CNT_LANE_SEL, lane) | + FIELD_PREP(DWC_PCIE_CNT_ENABLE, DWC_PCIE_PER_EVENT_OFF) | + FIELD_PREP(DWC_PCIE_EVENT_CLEAR, DWC_PCIE_EVENT_PER_CLEAR); + pci_write_config_dword(pdev, ras_des_offset + DWC_PCIE_EVENT_CNT_CTL, + ctrl); + } else if (type == DWC_PCIE_TIME_BASE_EVENT) { + /* + * TIME_BASED_ANAL_DATA_REG is a 64 bit register, we can safely + * use it with any manually controlled duration. And it is + * cleared when next measurement starts. + */ + ctrl = FIELD_PREP(DWC_PCIE_TIME_BASED_REPORT_SEL, event_id) | + FIELD_PREP(DWC_PCIE_TIME_BASED_DURATION_SEL, + DWC_PCIE_DURATION_MANUAL_CTL) | + DWC_PCIE_TIME_BASED_CNT_ENABLE; + pci_write_config_dword( + pdev, ras_des_offset + DWC_PCIE_TIME_BASED_ANAL_CTL, ctrl); + } + + if (flags & PERF_EF_START) + dwc_pcie_pmu_event_start(event, PERF_EF_RELOAD); + + perf_event_update_userpage(event); + + return 0; +} + +static void dwc_pcie_pmu_event_del(struct perf_event *event, int flags) +{ + struct dwc_pcie_pmu *pcie_pmu = to_dwc_pcie_pmu(event->pmu); + enum dwc_pcie_event_type type = DWC_PCIE_EVENT_TYPE(event); + + dwc_pcie_pmu_event_stop(event, flags | PERF_EF_UPDATE); + perf_event_update_userpage(event); + pcie_pmu->event[type] = NULL; +} + +static void dwc_pcie_pmu_remove_cpuhp_instance(void *hotplug_node) +{ + cpuhp_state_remove_instance_nocalls(dwc_pcie_pmu_hp_state, hotplug_node); +} + +/* + * Find the binded DES capability device info of a PCI device. + * @pdev: The PCI device. + */ +static struct dwc_pcie_dev_info *dwc_pcie_find_dev_info(struct pci_dev *pdev) +{ + struct dwc_pcie_dev_info *dev_info; + + list_for_each_entry(dev_info, &dwc_pcie_dev_info_head, dev_node) + if (dev_info->pdev == pdev) + return dev_info; + + return NULL; +} + +static void dwc_pcie_unregister_pmu(void *data) +{ + struct dwc_pcie_pmu *pcie_pmu = data; + + perf_pmu_unregister(&pcie_pmu->pmu); +} + +static bool dwc_pcie_match_des_cap(struct pci_dev *pdev) +{ + const struct dwc_pcie_vendor_id *vid; + u16 vsec = 0; + u32 val; + + if (!pci_is_pcie(pdev) || !(pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT)) + return false; + + for (vid = dwc_pcie_vendor_ids; vid->vendor_id; vid++) { + vsec = pci_find_vsec_capability(pdev, vid->vendor_id, + DWC_PCIE_VSEC_RAS_DES_ID); + if (vsec) + break; + } + if (!vsec) + return false; + + pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val); + if (PCI_VNDR_HEADER_REV(val) != 0x04) + return false; + + pci_dbg(pdev, + "Detected PCIe Vendor-Specific Extended Capability RAS DES\n"); + return true; +} + +static void dwc_pcie_unregister_dev(struct dwc_pcie_dev_info *dev_info) +{ + platform_device_unregister(dev_info->plat_dev); + list_del(&dev_info->dev_node); + kfree(dev_info); +} + +static int dwc_pcie_register_dev(struct pci_dev *pdev) +{ + struct platform_device *plat_dev; + struct dwc_pcie_dev_info *dev_info; + u32 bdf; + + bdf = PCI_DEVID(pdev->bus->number, pdev->devfn); + plat_dev = platform_device_register_data(NULL, "dwc_pcie_pmu", bdf, + pdev, sizeof(*pdev)); + + if (IS_ERR(plat_dev)) + return PTR_ERR(plat_dev); + + dev_info = kzalloc(sizeof(*dev_info), GFP_KERNEL); + if (!dev_info) + return -ENOMEM; + + /* Cache platform device to handle pci device hotplug */ + dev_info->plat_dev = plat_dev; + dev_info->pdev = pdev; + list_add(&dev_info->dev_node, &dwc_pcie_dev_info_head); + + return 0; +} + +static int dwc_pcie_pmu_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct pci_dev *pdev = to_pci_dev(dev); + struct dwc_pcie_dev_info *dev_info; + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + if (!dwc_pcie_match_des_cap(pdev)) + return NOTIFY_DONE; + if (dwc_pcie_register_dev(pdev)) + return NOTIFY_BAD; + break; + case BUS_NOTIFY_DEL_DEVICE: + dev_info = dwc_pcie_find_dev_info(pdev); + if (!dev_info) + return NOTIFY_DONE; + dwc_pcie_unregister_dev(dev_info); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block dwc_pcie_pmu_nb = { + .notifier_call = dwc_pcie_pmu_notifier, +}; + +static int dwc_pcie_pmu_probe(struct platform_device *plat_dev) +{ + struct pci_dev *pdev = plat_dev->dev.platform_data; + struct dwc_pcie_pmu *pcie_pmu; + char *name; + u32 bdf, val; + u16 vsec; + int ret; + + vsec = pci_find_vsec_capability(pdev, pdev->vendor, + DWC_PCIE_VSEC_RAS_DES_ID); + pci_read_config_dword(pdev, vsec + PCI_VNDR_HEADER, &val); + bdf = PCI_DEVID(pdev->bus->number, pdev->devfn); + name = devm_kasprintf(&plat_dev->dev, GFP_KERNEL, "dwc_rootport_%x", bdf); + if (!name) + return -ENOMEM; + + pcie_pmu = devm_kzalloc(&plat_dev->dev, sizeof(*pcie_pmu), GFP_KERNEL); + if (!pcie_pmu) + return -ENOMEM; + + pcie_pmu->pdev = pdev; + pcie_pmu->ras_des_offset = vsec; + pcie_pmu->nr_lanes = pcie_get_width_cap(pdev); + pcie_pmu->on_cpu = -1; + pcie_pmu->pmu = (struct pmu){ + .name = name, + .module = THIS_MODULE, + .attr_groups = dwc_pcie_attr_groups, + .capabilities = PERF_PMU_CAP_NO_EXCLUDE, + .task_ctx_nr = perf_invalid_context, + .event_init = dwc_pcie_pmu_event_init, + .add = dwc_pcie_pmu_event_add, + .del = dwc_pcie_pmu_event_del, + .start = dwc_pcie_pmu_event_start, + .stop = dwc_pcie_pmu_event_stop, + .read = dwc_pcie_pmu_event_update, + }; + + /* Add this instance to the list used by the offline callback */ + ret = cpuhp_state_add_instance(dwc_pcie_pmu_hp_state, + &pcie_pmu->cpuhp_node); + if (ret) { + pci_err(pdev, "Error %d registering hotplug @%x\n", ret, bdf); + return ret; + } + + /* Unwind when platform driver removes */ + ret = devm_add_action_or_reset(&plat_dev->dev, + dwc_pcie_pmu_remove_cpuhp_instance, + &pcie_pmu->cpuhp_node); + if (ret) + return ret; + + ret = perf_pmu_register(&pcie_pmu->pmu, name, -1); + if (ret) { + pci_err(pdev, "Error %d registering PMU @%x\n", ret, bdf); + return ret; + } + ret = devm_add_action_or_reset(&plat_dev->dev, dwc_pcie_unregister_pmu, + pcie_pmu); + if (ret) + return ret; + + return 0; +} + +static int dwc_pcie_pmu_online_cpu(unsigned int cpu, struct hlist_node *cpuhp_node) +{ + struct dwc_pcie_pmu *pcie_pmu; + + pcie_pmu = hlist_entry_safe(cpuhp_node, struct dwc_pcie_pmu, cpuhp_node); + if (pcie_pmu->on_cpu == -1) + pcie_pmu->on_cpu = cpumask_local_spread( + 0, dev_to_node(&pcie_pmu->pdev->dev)); + + return 0; +} + +static int dwc_pcie_pmu_offline_cpu(unsigned int cpu, struct hlist_node *cpuhp_node) +{ + struct dwc_pcie_pmu *pcie_pmu; + struct pci_dev *pdev; + int node; + cpumask_t mask; + unsigned int target; + + pcie_pmu = hlist_entry_safe(cpuhp_node, struct dwc_pcie_pmu, cpuhp_node); + /* Nothing to do if this CPU doesn't own the PMU */ + if (cpu != pcie_pmu->on_cpu) + return 0; + + pcie_pmu->on_cpu = -1; + pdev = pcie_pmu->pdev; + node = dev_to_node(&pdev->dev); + if (cpumask_and(&mask, cpumask_of_node(node), cpu_online_mask) && + cpumask_andnot(&mask, &mask, cpumask_of(cpu))) + target = cpumask_any(&mask); + else + target = cpumask_any_but(cpu_online_mask, cpu); + + if (target >= nr_cpu_ids) { + pci_err(pdev, "There is no CPU to set\n"); + return 0; + } + + /* This PMU does NOT support interrupt, just migrate context. */ + perf_pmu_migrate_context(&pcie_pmu->pmu, cpu, target); + pcie_pmu->on_cpu = target; + + return 0; +} + +static struct platform_driver dwc_pcie_pmu_driver = { + .probe = dwc_pcie_pmu_probe, + .driver = {.name = "dwc_pcie_pmu",}, +}; + +static int __init dwc_pcie_pmu_init(void) +{ + struct pci_dev *pdev = NULL; + bool found = false; + int ret; + + for_each_pci_dev(pdev) { + if (!dwc_pcie_match_des_cap(pdev)) + continue; + + ret = dwc_pcie_register_dev(pdev); + if (ret) { + pci_dev_put(pdev); + return ret; + } + + found = true; + } + if (!found) + return -ENODEV; + + ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, + "perf/dwc_pcie_pmu:online", + dwc_pcie_pmu_online_cpu, + dwc_pcie_pmu_offline_cpu); + if (ret < 0) + return ret; + + dwc_pcie_pmu_hp_state = ret; + + ret = platform_driver_register(&dwc_pcie_pmu_driver); + if (ret) + goto platform_driver_register_err; + + ret = bus_register_notifier(&pci_bus_type, &dwc_pcie_pmu_nb); + if (ret) + goto platform_driver_register_err; + notify = true; + + return 0; + +platform_driver_register_err: + cpuhp_remove_multi_state(dwc_pcie_pmu_hp_state); + + return ret; +} + +static void __exit dwc_pcie_pmu_exit(void) +{ + struct dwc_pcie_dev_info *dev_info, *tmp; + + if (notify) + bus_unregister_notifier(&pci_bus_type, &dwc_pcie_pmu_nb); + list_for_each_entry_safe(dev_info, tmp, &dwc_pcie_dev_info_head, dev_node) + dwc_pcie_unregister_dev(dev_info); + platform_driver_unregister(&dwc_pcie_pmu_driver); + cpuhp_remove_multi_state(dwc_pcie_pmu_hp_state); +} + +module_init(dwc_pcie_pmu_init); +module_exit(dwc_pcie_pmu_exit); + +MODULE_DESCRIPTION("PMU driver for DesignWare Cores PCI Express Controller"); +MODULE_AUTHOR("Shuai Xue "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c index 7eb8899e9b66..90ce4f0f327d 100644 --- a/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c +++ b/drivers/phy/rockchip/phy-rockchip-snps-pcie3.c @@ -32,7 +32,8 @@ #define RK3588_PCIE3PHY_GRF_CMN_CON0 0x0 #define RK3588_PCIE3PHY_GRF_PHY0_STATUS1 0x904 #define RK3588_PCIE3PHY_GRF_PHY1_STATUS1 0xa04 -#define RK3588_SRAM_INIT_DONE(reg) (reg & BIT(0)) +#define RK3588_SRAM_INIT_DONE(reg) ((reg & 0xff) == 0x49) +#define RK3588_SRAM_INIT_TIMEOUT 20000 struct rockchip_p3phy_ops; @@ -148,11 +149,14 @@ static int rockchip_p3phy_rk3588_init(struct rockchip_p3phy_priv *priv) ret = regmap_read_poll_timeout(priv->phy_grf, RK3588_PCIE3PHY_GRF_PHY0_STATUS1, reg, RK3588_SRAM_INIT_DONE(reg), - 0, 500); - ret |= regmap_read_poll_timeout(priv->phy_grf, - RK3588_PCIE3PHY_GRF_PHY1_STATUS1, - reg, RK3588_SRAM_INIT_DONE(reg), - 0, 500); + 100, RK3588_SRAM_INIT_TIMEOUT); + if (priv->pcie30_phymode == PHY_MODE_PCIE_AGGREGATION) { + ret |= regmap_read_poll_timeout(priv->phy_grf, + RK3588_PCIE3PHY_GRF_PHY1_STATUS1, + reg, RK3588_SRAM_INIT_DONE(reg), + 100, RK3588_SRAM_INIT_TIMEOUT); + } + if (ret) dev_err(&priv->phy->dev, "%s: lock failed 0x%x, check input refclk and power supply\n", __func__, reg); diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index cc8def371236..b50b59735f92 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -295,12 +295,12 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable) /* Keep things powered as long as CS is asserted */ pm_runtime_get_sync(rs->dev); - if (spi->cs_gpiod) + if (spi_get_csgpiod(spi, 0)) ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, 1); else ROCKCHIP_SPI_SET_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select)); } else { - if (spi->cs_gpiod) + if (spi_get_csgpiod(spi, 0)) ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, 1); else ROCKCHIP_SPI_CLR_BITS(rs->regs + ROCKCHIP_SPI_SER, BIT(spi->chip_select)); @@ -642,7 +642,7 @@ static int rockchip_spi_config(struct rockchip_spi *rs, cr0 |= (spi->mode & 0x3U) << CR0_SCPH_OFFSET; if (spi->mode & SPI_LSB_FIRST) cr0 |= CR0_FBM_LSB << CR0_FBM_OFFSET; - if (spi->mode & SPI_CS_HIGH) + if (spi->mode & SPI_CS_HIGH && !spi_get_csgpiod(spi, 0)) cr0 |= BIT(spi->chip_select) << CR0_SOI_OFFSET; if (xfer->rx_buf && xfer->tx_buf) { @@ -903,20 +903,15 @@ static int rockchip_spi_setup(struct spi_device *spi) struct rockchip_spi *rs = spi_controller_get_devdata(spi->controller); u32 cr0; - if (!spi->cs_gpiod && (spi->mode & SPI_CS_HIGH) && !rs->cs_high_supported) { - dev_warn(&spi->dev, "setup: non GPIO CS can't be active-high\n"); - return -EINVAL; - } - pm_runtime_get_sync(rs->dev); cr0 = readl_relaxed(rs->regs + ROCKCHIP_SPI_CTRLR0); cr0 &= ~(0x3 << CR0_SCPH_OFFSET); cr0 |= ((spi->mode & 0x3) << CR0_SCPH_OFFSET); - if (spi->mode & SPI_CS_HIGH && spi->chip_select <= 1) + if (spi->mode & SPI_CS_HIGH && spi->chip_select <= 1 && !spi_get_csgpiod(spi, 0)) cr0 |= BIT(spi->chip_select) << CR0_SOI_OFFSET; - else if (spi->chip_select <= 1) + else if (spi->chip_select <= 1 && !spi_get_csgpiod(spi, 0)) cr0 &= ~(BIT(spi->chip_select) << CR0_SOI_OFFSET); if (spi_controller_is_slave(spi->controller)) cr0 |= CR0_OPM_SLAVE << CR0_OPM_OFFSET; diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 432d0dc31c2f..e5e6bf4e9c8b 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -1911,6 +1911,8 @@ static const struct rockchip_tsadc_chip rk3506_tsadc_data = { .set_alarm_temp = rk_tsadcv3_alarm_temp, .set_tshut_temp = rk_tsadcv3_tshut_temp, .set_tshut_mode = rk_tsadcv4_tshut_mode, + .get_trim_code = rk_tsadcv2_get_trim_code, + .trim_slope = 594, .table = { .id = rk3506_code_table, .length = ARRAY_SIZE(rk3506_code_table), diff --git a/include/linux/aspm_ext.h b/include/linux/aspm_ext.h index c4580dfc80f7..140de4389796 100644 --- a/include/linux/aspm_ext.h +++ b/include/linux/aspm_ext.h @@ -17,6 +17,7 @@ static inline bool pcie_aspm_ext_is_in_l1sub_state(struct pci_dev *pdev) { retur enum rockchip_pcie_pm_ctrl_flag { ROCKCHIP_PCIE_PM_CTRL_RESET = 1, + ROCKCHIP_PCIE_PM_RETRAIN_LINK = 2, }; int rockchip_dw_pcie_pm_ctrl_for_user(struct pci_dev *dev, enum rockchip_pcie_pm_ctrl_flag flag); diff --git a/include/linux/pci.h b/include/linux/pci.h index 379ffe1da908..3f741b633909 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1230,6 +1230,8 @@ int pci_read_config_dword(const struct pci_dev *dev, int where, u32 *val); int pci_write_config_byte(const struct pci_dev *dev, int where, u8 val); int pci_write_config_word(const struct pci_dev *dev, int where, u16 val); int pci_write_config_dword(const struct pci_dev *dev, int where, u32 val); +void pci_clear_and_set_config_dword(const struct pci_dev *dev, int pos, + u32 clear, u32 set); int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val); int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 70b1d8dde991..0106b8a0cd99 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2592,6 +2592,8 @@ #define PCI_VENDOR_ID_TEKRAM 0x1de1 #define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29 +#define PCI_VENDOR_ID_ALIBABA 0x1ded + #define PCI_VENDOR_ID_TEHUTI 0x1fc9 #define PCI_DEVICE_ID_TEHUTI_3009 0x3009 #define PCI_DEVICE_ID_TEHUTI_3010 0x3010