diff --git a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dts b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dts index cf105f8eecc4..f3a7677ba283 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dts +++ b/arch/arm64/boot/dts/rockchip/rv1126b-evb2-v10.dts @@ -585,7 +585,7 @@ }; &sc850sl { - reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_LOW>; + reset-gpios = <&gpio4 RK_PA7 GPIO_ACTIVE_HIGH>; }; &sdmmc0 { diff --git a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi index f6a66bcab364..e50a2ab934fb 100644 --- a/arch/arm64/boot/dts/rockchip/rv1126b.dtsi +++ b/arch/arm64/boot/dts/rockchip/rv1126b.dtsi @@ -308,15 +308,15 @@ nvmem-cell-names = "leakage"; rockchip,pvtm-voltage-sel = < - 0 1639 0 - 1640 1684 1 - 1685 1729 2 - 1730 1774 3 - 1775 1819 4 - 1820 1864 5 - 1865 1909 6 - 1910 1954 7 - 1955 1999 8 + 0 1669 0 + 1670 1714 1 + 1715 1759 2 + 1760 1804 3 + 1805 1849 4 + 1850 1894 5 + 1895 1939 6 + 1940 1984 7 + 1985 2029 8 >; rockchip,pvtm-pvtpll; rockchip,pvtm-offset = <0x54>; @@ -354,52 +354,44 @@ }; opp-1200000000 { opp-hz = /bits/ 64 <1200000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <900000 900000 1100000>; opp-microvolt-L0 = <950000 950000 1100000>; opp-microvolt-L1 = <925000 925000 1100000>; clock-latency-ns = <40000>; }; opp-1296000000 { opp-hz = /bits/ 64 <1296000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <950000 950000 1100000>; opp-microvolt-L0 = <1000000 1000000 1100000>; opp-microvolt-L1 = <975000 975000 1100000>; - opp-microvolt-L2 = <950000 950000 1100000>; - opp-microvolt-L3 = <925000 925000 1100000>; clock-latency-ns = <40000>; }; opp-1416000000 { opp-hz = /bits/ 64 <1416000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <950000 950000 1100000>; opp-microvolt-L0 = <1025000 1025000 1100000>; opp-microvolt-L1 = <1000000 1000000 1100000>; opp-microvolt-L2 = <975000 975000 1100000>; - opp-microvolt-L3 = <950000 950000 1100000>; - opp-microvolt-L4 = <925000 925000 1100000>; clock-latency-ns = <40000>; }; opp-1512000000 { opp-hz = /bits/ 64 <1512000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <950000 950000 1100000>; opp-microvolt-L0 = <1050000 1050000 1100000>; opp-microvolt-L1 = <1025000 1025000 1100000>; opp-microvolt-L2 = <1000000 1000000 1100000>; opp-microvolt-L3 = <975000 975000 1100000>; - opp-microvolt-L4 = <950000 950000 1100000>; - opp-microvolt-L5 = <925000 925000 1100000>; clock-latency-ns = <40000>; }; opp-1608000000 { opp-hz = /bits/ 64 <1608000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <950000 950000 1100000>; opp-microvolt-L0 = <1100000 1100000 1100000>; opp-microvolt-L1 = <1075000 1075000 1100000>; opp-microvolt-L2 = <1050000 1050000 1100000>; opp-microvolt-L3 = <1025000 1025000 1100000>; opp-microvolt-L4 = <1000000 1000000 1100000>; opp-microvolt-L5 = <975000 975000 1100000>; - opp-microvolt-L6 = <950000 950000 1100000>; - opp-microvolt-L7 = <925000 925000 1100000>; clock-latency-ns = <40000>; }; }; @@ -3321,37 +3313,31 @@ opp-396000000 { opp-hz = /bits/ 64 <396000000>; - opp-microvolt = <850000 850000 1000000>; + opp-microvolt = <850000 850000 1050000>; opp-microvolt-L0 = <900000 900000 1050000>; opp-microvolt-L1 = <875000 875000 1050000>; }; opp-700000000 { opp-hz = /bits/ 64 <700000000>; - opp-microvolt = <850000 850000 1000000>; + opp-microvolt = <850000 850000 1050000>; opp-microvolt-L0 = <900000 900000 1050000>; opp-microvolt-L1 = <875000 875000 1050000>; }; opp-800000000 { opp-hz = /bits/ 64 <800000000>; - opp-microvolt = <850000 850000 1000000>; + opp-microvolt = <900000 900000 1050000>; opp-microvolt-L0 = <925000 925000 1050000>; - opp-microvolt-L1 = <900000 900000 1050000>; - opp-microvolt-L2 = <875000 875000 1050000>; }; opp-900000000 { opp-hz = /bits/ 64 <900000000>; - opp-microvolt = <900000 900000 1000000>; + opp-microvolt = <950000 950000 1050000>; opp-microvolt-L0 = <975000 975000 1050000>; - opp-microvolt-L1 = <950000 950000 1050000>; - opp-microvolt-L2 = <925000 925000 1050000>; }; opp-950000000 { opp-hz = /bits/ 64 <950000000>; - opp-microvolt = <900000 900000 1050000>; + opp-microvolt = <950000 950000 1050000>; opp-microvolt-L0 = <1000000 1000000 1050000>; opp-microvolt-L1 = <975000 975000 1050000>; - opp-microvolt-L2 = <950000 950000 1050000>; - opp-microvolt-L3 = <925000 925000 1050000>; }; }; diff --git a/drivers/clk/rockchip/clk-pvtpll.c b/drivers/clk/rockchip/clk-pvtpll.c index 22289bf57bac..ff21f7e258ce 100644 --- a/drivers/clk/rockchip/clk-pvtpll.c +++ b/drivers/clk/rockchip/clk-pvtpll.c @@ -152,10 +152,10 @@ static struct pvtpll_table rv1126b_aisp_pvtpll_table[] = { static struct pvtpll_table rv1126b_core_pvtpll_table[] = { /* rate_hz, ring_sel, length */ - ROCKCHIP_PVTPLL_VOLT_SEL(1608000000, 0, 30, 0), - ROCKCHIP_PVTPLL_VOLT_SEL(1512000000, 0, 30, 7), - ROCKCHIP_PVTPLL_VOLT_SEL(1416000000, 0, 34, 6), - ROCKCHIP_PVTPLL_VOLT_SEL(1296000000, 0, 38, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(1608000000, 0, 30, 7), + ROCKCHIP_PVTPLL_VOLT_SEL(1512000000, 0, 30, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(1416000000, 0, 34, 4), + ROCKCHIP_PVTPLL_VOLT_SEL(1296000000, 0, 38, 3), ROCKCHIP_PVTPLL_VOLT_SEL(1200000000, 0, 38, 3), ROCKCHIP_PVTPLL_VOLT_SEL(1008000000, 0, 52, 3), ROCKCHIP_PVTPLL_VOLT_SEL(816000000, 0, 84, 3), @@ -173,10 +173,10 @@ static struct pvtpll_table rv1126b_isp_pvtpll_table[] = { static struct pvtpll_table rv1126b_npu_pvtpll_table[] = { /* rate_hz, ring_se, length, volt_sel_thr */ - ROCKCHIP_PVTPLL_VOLT_SEL(1000000000, 0, 12, 7), - ROCKCHIP_PVTPLL_VOLT_SEL(950000000, 0, 12, 5), - ROCKCHIP_PVTPLL_VOLT_SEL(900000000, 0, 14, 4), - ROCKCHIP_PVTPLL_VOLT_SEL(800000000, 0, 16, 4), + ROCKCHIP_PVTPLL_VOLT_SEL(1000000000, 0, 12, 5), + ROCKCHIP_PVTPLL_VOLT_SEL(950000000, 0, 12, 3), + ROCKCHIP_PVTPLL_VOLT_SEL(900000000, 0, 14, 2), + ROCKCHIP_PVTPLL_VOLT_SEL(800000000, 0, 16, 2), ROCKCHIP_PVTPLL_VOLT_SEL(700000000, 0, 36, 3), }; diff --git a/drivers/gpu/drm/rockchip/dw-dp.c b/drivers/gpu/drm/rockchip/dw-dp.c index 843ac09a17a3..d77c05ccd6c2 100644 --- a/drivers/gpu/drm/rockchip/dw-dp.c +++ b/drivers/gpu/drm/rockchip/dw-dp.c @@ -4145,7 +4145,8 @@ static int dw_dp_mst_find_ext_bridges(struct dw_dp *dp) return ret; if (mst_enc->next_bridge) { - ret = drm_bridge_attach(&mst_enc->encoder, mst_enc->next_bridge, NULL, 0); + ret = drm_bridge_attach(&mst_enc->encoder, mst_enc->next_bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) { DRM_DEV_ERROR(dp->dev, "failed to attach next bridge: %d\n", ret); return ret; diff --git a/drivers/gpu/drm/rockchip/rockchip_dp_mst_aux_client.c b/drivers/gpu/drm/rockchip/rockchip_dp_mst_aux_client.c index 6baf5039fb54..d7bc91adc841 100644 --- a/drivers/gpu/drm/rockchip/rockchip_dp_mst_aux_client.c +++ b/drivers/gpu/drm/rockchip/rockchip_dp_mst_aux_client.c @@ -183,6 +183,7 @@ static int rockchip_dp_aux_client_parse(struct rockchip_dp_aux_client *aux_clien struct drm_display_mode mode_buf, *mode = &mode_buf; int rc, port_num, i; struct edid *edid; + char name[10]; const u8 edid_buf[EDID_LENGTH] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x44, 0x6D, @@ -205,13 +206,18 @@ static int rockchip_dp_aux_client_parse(struct rockchip_dp_aux_client *aux_clien if (!ports) return -ENOMEM; - i = 0; - for_each_child_of_node(of_node, node) { + for (i = 0; i < port_num; i++) { struct display_timing dt; struct videomode vm; + snprintf(name, sizeof(name), "mst-dp%d", i); + node = of_get_child_by_name(of_node, name); + if (!node) + return -EINVAL; + edid = kzalloc(sizeof(*edid), GFP_KERNEL); if (!edid) { + of_node_put(node); rc = -ENOMEM; goto fail; } @@ -222,13 +228,13 @@ static int rockchip_dp_aux_client_parse(struct rockchip_dp_aux_client *aux_clien drm_display_mode_from_videomode(&vm, mode); rockchip_dp_sim_update_dtd(edid, mode); } + of_node_put(node); rockchip_dp_sim_update_checksum(edid); memcpy(&ports[i], &output_port, sizeof(*ports)); ports[i].peer_guid[0] = i; ports[i].edid = (u8 *)edid; ports[i].edid_size = sizeof(*edid); - i++; } rc = rockchip_dp_mst_sim_update(aux_client->mst_ctx, port_num, ports); diff --git a/drivers/media/i2c/sc450ai.c b/drivers/media/i2c/sc450ai.c index b55baa096692..59273dba8f63 100644 --- a/drivers/media/i2c/sc450ai.c +++ b/drivers/media/i2c/sc450ai.c @@ -408,10 +408,11 @@ static const struct regval sc450ai_linear_10_2688x1520_30fps_2lane_regs[] = { {0x3209, 0x80}, {0x320a, 0x05}, {0x320b, 0xf0}, - {0x320c, 0x02}, + {0x320c, 0x02}, //hts {0x320d, 0xee}, - {0x320e, 0x06}, - {0x320f, 0x18}, + {0x320e, 0x06}, //vts + // {0x320f, 0x18}, + {0x320f, 0x38}, {0x3214, 0x11}, {0x3215, 0x11}, {0x3220, 0x00}, @@ -1197,7 +1198,7 @@ static const struct sc450ai_mode supported_modes_2lane[] = { }, .exp_def = 0x0080,//mark .hts_def = 0x2ee * 4, - .vts_def = 0x0618, + .vts_def = 0x0638, .bus_fmt = MEDIA_BUS_FMT_SBGGR10_1X10, .reg_list = sc450ai_linear_10_2688x1520_30fps_2lane_regs, .hdr_mode = NO_HDR, diff --git a/drivers/media/platform/rockchip/avsp/avsp.c b/drivers/media/platform/rockchip/avsp/avsp.c index 3f9ad5a92676..c28de5f0ade9 100644 --- a/drivers/media/platform/rockchip/avsp/avsp.c +++ b/drivers/media/platform/rockchip/avsp/avsp.c @@ -342,12 +342,14 @@ static int avsp_rcs_run(struct file *file, struct rkavsp_rcs_in_out *buf) writel(val, base + AVSP_RCS_WR_C_BASE); break; case AVSP_MODE_FBCE: - out_offs = rcs_wr_stride_c * in_h; c_addr = val + (rcs_out_start_offset / 64) * 16; writel(c_addr, base + AVSP_RCS_WR_C_BASE); - val += ((rcs_out_start_offset / 64) * 384); + out_offs = rcs_wr_stride_c * in_h + ((rcs_out_start_offset / 64) * 384); val += out_offs; writel(val, base + AVSP_RCS_WR_Y_BASE); + + val = out_offs; + writel(val << 4, base + AVSP_RCS_WR_FBCE_HEAD_OFFSET); break; default: val += (rcs_out_start_offset * 6); diff --git a/drivers/media/platform/rockchip/fec/fec_offline.c b/drivers/media/platform/rockchip/fec/fec_offline.c index 95ef4ef2904b..b89146a6126b 100644 --- a/drivers/media/platform/rockchip/fec/fec_offline.c +++ b/drivers/media/platform/rockchip/fec/fec_offline.c @@ -21,6 +21,10 @@ static int rkfec_cache_linesize = 2; module_param_named(cache_linesize, rkfec_cache_linesize, int, 0644); MODULE_PARM_DESC(cache_linesize, "Cache linesize (0-3)"); +static int rkfec_user_debug; +module_param_named(user_debug, rkfec_user_debug, int, 0644); +MODULE_PARM_DESC(user_debug, "Debug level (0-6)"); + #if IS_LINUX_VERSION_AT_LEAST_6_1 #define GET_SG_TABLE(mem_ops, off_buf) mem_ops->cookie(&(off_buf)->vb, (off_buf)->mem) #else @@ -273,8 +277,13 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) u32 val; u32 in_w = buf->in_width, in_h = buf->in_height; u32 out_w = buf->out_width, out_h = buf->out_height; + /* Calculate virtual width in bytes */ u32 in_stride, out_stride_y, out_stride_uv; + /* Calculate uv offset in bytes */ u32 in_uv_offset, out_uv_offset; + /* Calculate byte offset based on pixel offset */ + u32 in_y_start = 0, in_uv_start = 0, out_y_start = 0, out_uv_start = 0; + u32 y_base, c_base; void __iomem *base = ofl->hw->base_addr; int ret = -EINVAL; ktime_t t = 0; @@ -289,6 +298,11 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) buf->out_fourcc, buf->out_fourcc >> 8, buf->out_fourcc >> 16, buf->out_fourcc >> 24); + v4l2_dbg(3, rkfec_debug, &ofl->v4l2_dev, + "in: stride %d, offset %d, out: stride %d, offset %d\n", + buf->buf_cfg.in_stride, buf->buf_cfg.in_offs, + buf->buf_cfg.out_stride, buf->buf_cfg.out_offs); + if (hw->fec_ver == RKFEC_V20) { if (hw->soft_reset) hw->soft_reset(hw); @@ -310,14 +324,18 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) case V4L2_PIX_FMT_NV12: in_fmt = SW_FEC_RD_FMT(1); rd_mode = SW_FEC_RD_MODE(0); - in_stride = (buf->buf_cfg.in_stride + 15) / 16 * 16; + in_stride = ALIGN(buf->buf_cfg.in_stride, 16); in_uv_offset = in_stride * in_h; + in_y_start = buf->buf_cfg.in_offs; + in_uv_start = in_y_start; break; case V4L2_PIX_FMT_TILE420: in_fmt = SW_FEC_RD_FMT(0); rd_mode = SW_FEC_RD_MODE(1); - in_stride = (buf->buf_cfg.in_stride * 6 + 15) / 16 * 16; + in_stride = ALIGN(buf->buf_cfg.in_stride * 6, 16); in_uv_offset = in_stride * in_h; + in_y_start = buf->buf_cfg.in_offs * 6; + in_uv_start = in_y_start; break; default: v4l2_err(&ofl->v4l2_dev, @@ -331,16 +349,20 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) case V4L2_PIX_FMT_NV12: out_fmt = SW_FEC_WR_FMT(1); wr_mode = SW_FEC_WR_MODE(0); - out_stride_y = (buf->buf_cfg.out_stride + 15) / 16 * 16; + out_stride_y = ALIGN(buf->buf_cfg.out_stride, 16); out_stride_uv = out_stride_y; out_uv_offset = out_stride_y * out_h; + out_y_start = buf->buf_cfg.out_offs; + out_uv_start = out_y_start; break; case V4L2_PIX_FMT_TILE420: out_fmt = SW_FEC_WR_FMT(0); wr_mode = SW_FEC_WR_MODE(1); - out_stride_y = (buf->buf_cfg.out_stride * 6 + 15) / 16 * 16; + out_stride_y = ALIGN(buf->buf_cfg.out_stride * 6, 16); out_stride_uv = out_stride_y; out_uv_offset = out_stride_y * out_h; + out_y_start = buf->buf_cfg.out_offs * 6; + out_uv_start = out_y_start; break; case V4L2_PIX_FMT_FBC0: out_fmt = SW_FEC_WR_FMT(0); @@ -349,13 +371,24 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) out_stride_uv = (buf->buf_cfg.out_stride + 63) / 64 * 16; // Head stride is c channel out_uv_offset = out_stride_uv * out_h / 4; + out_y_start = buf->buf_cfg.out_offs / 64 * 384; + out_uv_start = buf->buf_cfg.out_offs / 64 * 16; break; case V4L2_PIX_FMT_QUAD: out_fmt = SW_FEC_WR_FMT(0); wr_mode = SW_FEC_WR_MODE(3); - out_stride_y = (buf->buf_cfg.out_stride * 3 + 15) / 16 * 16; + out_stride_y = ALIGN(buf->buf_cfg.out_stride * 3, 16); out_stride_uv = out_stride_y; out_uv_offset = out_stride_y * out_h; + + if (buf->buf_cfg.out_offs > 0) { + v4l2_err(&ofl->v4l2_dev, + "Offset is not supported in %c%c%c%c\n", + buf->out_fourcc, buf->out_fourcc >> 8, + buf->out_fourcc >> 16, buf->out_fourcc >> 24); + out_y_start = 0; + out_uv_start = 0; + } break; default: v4l2_err(&ofl->v4l2_dev, "no support out format:%c%c%c%c\n", @@ -372,11 +405,10 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) sg_talbe = GET_SG_TABLE(mem_ops, off_buf); if (!sg_talbe) goto free_buf; - val = sg_dma_address(sg_talbe->sgl); - val += buf->buf_cfg.in_offs; - writel(val, base + RKFEC_RD_Y_BASE); - val += in_uv_offset; - writel(val, base + RKFEC_RD_C_BASE); + y_base = sg_dma_address(sg_talbe->sgl); + c_base = y_base + in_uv_offset; + writel(y_base + in_y_start, base + RKFEC_RD_Y_BASE); + writel(c_base + in_uv_start, base + RKFEC_RD_C_BASE); /* output picture buf */ off_buf = buf_add(file, buf->buf_cfg.out_pic_fd, buf->buf_cfg.out_size); @@ -386,21 +418,21 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) sg_talbe = GET_SG_TABLE(mem_ops, off_buf); if (!sg_talbe) goto free_buf; - val = sg_dma_address(sg_talbe->sgl); if (buf->out_fourcc == V4L2_PIX_FMT_FBC0) { - val += buf->buf_cfg.out_offs; - writel(val, base + RKFEC_WR_C_BASE); - val += out_uv_offset; - writel(val, base + RKFEC_WR_Y_BASE); + c_base = sg_dma_address(sg_talbe->sgl); + y_base = c_base + out_uv_offset; - val = SW_FEC_WR_FBCE_HEAD_OFFSET(out_uv_offset); - writel(val, base + RKFEC_WR_FBCE_HEAD_OFFSET); + if (buf->buf_cfg.out_offs > 0) + writel((out_uv_offset + out_y_start) << 4, + base + RKFEC_WR_FBCE_HEAD_OFFSET); + else + writel(out_uv_offset << 4, base + RKFEC_WR_FBCE_HEAD_OFFSET); } else { - val += buf->buf_cfg.out_offs; - writel(val, base + RKFEC_WR_Y_BASE); - val += out_uv_offset; - writel(val, base + RKFEC_WR_C_BASE); + y_base = sg_dma_address(sg_talbe->sgl); + c_base = y_base + out_uv_offset; } + writel(y_base + out_y_start, base + RKFEC_WR_Y_BASE); + writel(c_base + out_uv_start, base + RKFEC_WR_C_BASE); /* lut buf */ off_buf = buf_add(file, buf->buf_cfg.lut_fd, buf->buf_cfg.lut_size); @@ -465,14 +497,16 @@ static int fec_running(struct file *file, struct rkfec_in_out *buf) ofl->in_fmt.width = in_w; ofl->in_fmt.height = in_h; ofl->in_fmt.pixelformat = buf->in_fourcc; - ofl->in_fmt.bytesperline = buf->buf_cfg.in_stride; + ofl->in_fmt.bytesperline = in_stride; ofl->in_fmt.sizeimage = buf->buf_cfg.in_size; + ofl->in_fmt.offset = buf->buf_cfg.in_offs; ofl->out_fmt.width = out_w; ofl->out_fmt.height = out_h; ofl->out_fmt.pixelformat = buf->out_fourcc; - ofl->out_fmt.bytesperline = buf->buf_cfg.out_stride; + ofl->out_fmt.bytesperline = out_stride_y; ofl->out_fmt.sizeimage = buf->buf_cfg.out_size; + ofl->out_fmt.offset = buf->buf_cfg.out_offs; ret = wait_for_completion_timeout(&ofl->cmpl, msecs_to_jiffies(300)); if (!ret) { diff --git a/drivers/media/platform/rockchip/fec/procfs.c b/drivers/media/platform/rockchip/fec/procfs.c index aabfe8bd9c40..28b494550a1d 100644 --- a/drivers/media/platform/rockchip/fec/procfs.c +++ b/drivers/media/platform/rockchip/fec/procfs.c @@ -37,13 +37,21 @@ static void offline_fec_show_hw(struct seq_file *p, struct rkfec_hw_dev *hw) "4x4" }; + static const char * const cacheline[] = { + "64B", + "64B", + "128B", + "128B" + }; + if (hw->dev->power.usage_count.counter <= 0) { seq_printf(p, "\n%s\n", "HW close"); return; } val = readl(hw->base_addr + RKFEC_CTRL); - seq_printf(p, "%-10s RD_fmt:%s RD_mode:%s WR_fmt:%s WR_mode:%s WR_fbce:%s (0x%x)\n", "CTRL", + seq_printf(p, "%-10s RD_fmt:%s RD_mode:%s WR_fmt:%s WR_mode:%s WR_fbce_unc:%s (0x%x)\n", + "CTRL", val & BIT(2) ? "semi" : "interleave", (val >> 4) & 0x3 ? "semi" : "rast", val & BIT(8) ? "semi" : "interleave", wr_mode[val >> 9], @@ -75,6 +83,9 @@ static void offline_fec_show_hw(struct seq_file *p, struct rkfec_hw_dev *hw) val = readl(hw->base_addr + RKFEC_STATUS1); seq_printf(p, "%-10s 0x%x\n", "STATUS1", val & 0x3FFFFF); + + val = readl(hw->base_addr + RKFEC_CACHE_CTRL); + seq_printf(p, "%-10s %s\n", "Cacheline", cacheline[(val >> 4) & 0x3]); } static int offline_fec_show(struct seq_file *p, void *v) @@ -110,7 +121,7 @@ static int offline_fec_show(struct seq_file *p, void *v) ofl->debug.frameloss, ofl->debug.frame_timeout_cnt); - seq_printf(p, "%-10s Format:%c%c%c%c Size:%dx%d Sizeimage(%d) (frame:%d rate:%dms frameloss:%d\n", + seq_printf(p, "%-10s Format:%c%c%c%c Size:%dx%d Offset(%d) Sizeimage(%d) (frame:%d rate:%dms frameloss:%d\n", "Output", ofl->out_fmt.pixelformat, ofl->out_fmt.pixelformat >> 8, @@ -118,6 +129,7 @@ static int offline_fec_show(struct seq_file *p, void *v) ofl->out_fmt.pixelformat >> 24, ofl->out_fmt.width, ofl->out_fmt.height, + ofl->out_fmt.offset, ofl->out_fmt.sizeimage, ofl->curr_frame.fe_seq, (u32)(ofl->curr_frame.fe_timestamp - ofl->prev_frame.fe_timestamp) / 1000 / 1000, diff --git a/drivers/media/platform/rockchip/ispp/fec.c b/drivers/media/platform/rockchip/ispp/fec.c index 643322314fab..113a932faaca 100644 --- a/drivers/media/platform/rockchip/ispp/fec.c +++ b/drivers/media/platform/rockchip/ispp/fec.c @@ -18,6 +18,10 @@ #include "stream.h" #include "common.h" +static int rkfec_user_debug; +module_param_named(user_debug, rkfec_user_debug, int, 0644); +MODULE_PARM_DESC(user_debug, "Debug level (0-6)"); + struct rkispp_fec_buf { struct list_head list; struct file *file; diff --git a/drivers/misc/rockchip/pcie-rkep.c b/drivers/misc/rockchip/pcie-rkep.c index 897fa25eee1c..717e049f8cfd 100644 --- a/drivers/misc/rockchip/pcie-rkep.c +++ b/drivers/misc/rockchip/pcie-rkep.c @@ -558,6 +558,14 @@ static int pcie_rkep_mmap(struct file *file, struct vm_area_struct *vma) } addr = pci_resource_start(dev, 0); break; + case PCIE_EP_MMAP_RESOURCE_BAR1: + bar_size = pci_resource_len(dev, 1); + if (size > bar_size) { + dev_warn(&pcie_rkep->pdev->dev, "bar1 mmap size is out of limitation\n"); + return -EINVAL; + } + addr = pci_resource_start(dev, 1); + break; case PCIE_EP_MMAP_RESOURCE_BAR2: bar_size = pci_resource_len(dev, 2); if (size > bar_size) { @@ -574,6 +582,14 @@ static int pcie_rkep_mmap(struct file *file, struct vm_area_struct *vma) } addr = pci_resource_start(dev, 4); break; + case PCIE_EP_MMAP_RESOURCE_BAR5: + bar_size = pci_resource_len(dev, 5); + if (size > bar_size) { + dev_warn(&pcie_rkep->pdev->dev, "bar5 mmap size is out of limitation\n"); + return -EINVAL; + } + addr = pci_resource_start(dev, 5); + break; case PCIE_EP_MMAP_RESOURCE_USER_MEM: if (size > RKEP_USER_MEM_SIZE) { dev_warn(&pcie_rkep->pdev->dev, "mmap size is out of limitation\n"); diff --git a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c index 5dfce987edc6..3b48bf92a139 100644 --- a/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-ep-rockchip.c @@ -22,6 +22,7 @@ #include #include +#include "../../pci.h" #include "../rockchip-pcie-dma.h" #include "pcie-designware.h" #include "pcie-dw-dmatest.h" @@ -35,6 +36,17 @@ #define to_rockchip_pcie(x) dev_get_drvdata((x)->dev) +#define RK_PCIE_DBG 0 + +#define PCIE_CLIENT_DBG_FIFO_MODE_CON 0x310 +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0 0x320 +#define PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1 0x324 +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0 0x328 +#define PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1 0x32c +#define PCIE_CLIENT_DBG_FIFO_STATUS 0x350 +#define PCIE_CLIENT_DBG_TRANSITION_DATA 0xffff0000 +#define PCIE_CLIENT_DBF_EN 0xffff0007 + #define PCIE_DMA_OFFSET 0x380000 #define PCIE_DMA_CTRL_OFF 0x8 @@ -114,6 +126,8 @@ #define PCIE_BAR_MAX_NUM 6 #define PCIE_HOTRESET_TMOUT_US 10000 +#define PCIE_WAKE_DELAY_US 2000 /* 2 ms */ + struct rockchip_pcie { struct dw_pcie pci; void __iomem *apb_base; @@ -121,7 +135,11 @@ struct rockchip_pcie { struct clk_bulk_data *clks; int clk_cnt; struct reset_control *rst; - struct gpio_desc *rst_gpio; + struct gpio_desc *perst_gpio; + struct gpio_desc *wake_gpio; + int perst_irq; + bool ep_power_independent; + struct completion ep_perst_deassert_complete; unsigned long *ib_window_map; unsigned long *ob_window_map; u32 num_ib_windows; @@ -160,6 +178,8 @@ static const struct of_device_id rockchip_pcie_ep_of_match[] = { MODULE_DEVICE_TABLE(of, rockchip_pcie_ep_of_match); +static irqreturn_t rockchip_pcie_perst_irq_handler(int irq, void *arg); + static void rockchip_pcie_devmode_update(struct rockchip_pcie *rockchip, int mode, int submode) { rockchip->obj_info->devmode.mode = mode; @@ -215,10 +235,24 @@ static int rockchip_pcie_get_io_resource(struct platform_device *pdev, char name[8]; int i, idx; - rockchip->rst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); - if (IS_ERR(rockchip->rst_gpio)) { + rockchip->perst_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_IN); + if (IS_ERR(rockchip->perst_gpio)) { dev_err(dev, "Failed to get reset gpio\n"); - return PTR_ERR(rockchip->rst_gpio); + return PTR_ERR(rockchip->perst_gpio); + } + + if (device_property_read_bool(dev, "rockchip,ep-power-independent")) { + rockchip->ep_power_independent = true; + if (!rockchip->perst_gpio) { + dev_err(dev, "When the EP power supply is independent of the RC, the perst_gpio is necessary\n"); + return -EINVAL; + } + } + + rockchip->wake_gpio = devm_gpiod_get_optional(dev, "wake", GPIOD_OUT_LOW); + if (IS_ERR(rockchip->wake_gpio)) { + dev_err(dev, "Failed to get wake gpio\n"); + return PTR_ERR(rockchip->wake_gpio); } apb_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pcie-apb"); @@ -311,6 +345,8 @@ static int rockchip_pcie_get_io_resource(struct platform_device *pdev, return -ENODEV; } + rockchip->pci.link_gen = of_pci_get_max_link_speed(np); + return 0; } @@ -350,7 +386,17 @@ static int rockchip_pcie_get_resource(struct platform_device *pdev, return -EINVAL; } - return 0; + if (rockchip->perst_gpio) { + rockchip->perst_irq = gpiod_to_irq(rockchip->perst_gpio); + ret = devm_request_threaded_irq(&pdev->dev, rockchip->perst_irq, NULL, + rockchip_pcie_perst_irq_handler, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT | IRQF_NO_AUTOEN, + "perst_irq", rockchip); + if (ret) + dev_err(&pdev->dev, "Failed to request PERST IRQ\n"); + } + + return ret; } static int rockchip_pci_find_ext_capability(struct rockchip_pcie *rockchip, int cap) @@ -423,6 +469,11 @@ static void rockchip_pcie_resize_bar_nsticky(struct rockchip_pcie *rockchip) dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0x2c0); rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32); + bar = BAR_1; + dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0x10); + dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0xc0); + rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32); + bar = BAR_2; dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0x400); dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0x6c0); @@ -434,11 +485,18 @@ static void rockchip_pcie_resize_bar_nsticky(struct rockchip_pcie *rockchip) dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0xc0); rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32); + bar = BAR_5; + dw_pcie_writel_dbi(pci, resbar_base + 0x4 + bar * 0x8, 0x10); + dw_pcie_writel_dbi(pci, resbar_base + 0x8 + bar * 0x8, 0xc0); + rockchip_pcie_ep_set_bar_flag(rockchip, bar, PCI_BASE_ADDRESS_MEM_TYPE_32); + /* Disable BAR1 BAR5*/ bar = BAR_1; - dw_pcie_writel_dbi(pci, PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + bar * 4, 0); + if (!rockchip->ib_target_size[bar]) + dw_pcie_writel_dbi(pci, PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + bar * 4, 0); bar = BAR_5; - dw_pcie_writel_dbi(pci, PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + bar * 4, 0); + if (!rockchip->ib_target_size[bar]) + dw_pcie_writel_dbi(pci, PCIE_TYPE0_HDR_DBI2_OFFSET + 0x10 + bar * 4, 0); dw_pcie_dbi_ro_wr_dis(&rockchip->pci); } @@ -531,6 +589,38 @@ static int rockchip_pcie_poll_irq_user(struct rockchip_pcie *rockchip, struct pc return 0; } +static int rockchip_pcie_perst_deassert(struct rockchip_pcie *rockchip) +{ + gpiod_set_value_cansleep(rockchip->wake_gpio, 0); + usleep_range(PCIE_WAKE_DELAY_US, PCIE_WAKE_DELAY_US + 500); + gpiod_set_value_cansleep(rockchip->wake_gpio, 1); + + if (rockchip->ep_power_independent) + complete(&rockchip->ep_perst_deassert_complete); + + return 0; +} + +static irqreturn_t rockchip_pcie_perst_irq_handler(int irq, void *arg) +{ + struct rockchip_pcie *rockchip = arg; + struct device *dev = rockchip->pci.dev; + u32 perst; + + perst = gpiod_get_value(rockchip->perst_gpio); + if (perst) { + dev_dbg(dev, "PERST asserted by host. Shutting down the PCIe link!\n"); + } else { + dev_dbg(dev, "PERST de-asserted by host. Starting link training!\n"); + rockchip_pcie_perst_deassert(rockchip); + } + + irq_set_irq_type(gpiod_to_irq(rockchip->perst_gpio), + (perst ? IRQF_TRIGGER_HIGH : IRQF_TRIGGER_LOW)); + + return IRQ_HANDLED; +} + static irqreturn_t rockchip_pcie_sys_irq_handler(int irq, void *arg) { struct rockchip_pcie *rockchip = arg; @@ -654,6 +744,18 @@ static int rockchip_pcie_init_host(struct rockchip_pcie *rockchip) struct device *dev = rockchip->pci.dev; int ret; + if (rockchip->ep_power_independent && gpiod_get_value(rockchip->perst_gpio)) { + init_completion(&rockchip->ep_perst_deassert_complete); + dev_info(dev, "Waiting for perst# de-assert\n"); + enable_irq(rockchip->perst_irq); + ret = wait_for_completion_timeout(&rockchip->ep_perst_deassert_complete, 30 * HZ); + if (!ret) { + dev_err(dev, "Not waiting for a valid PERST signal\n"); + return ret; + } + dev_info(dev, "perst# de-assert\n"); + } + ret = clk_bulk_prepare_enable(rockchip->clk_cnt, rockchip->clks); if (ret) return 0; @@ -739,12 +841,39 @@ static void rockchip_pcie_hide_broken_ats_cap(struct dw_pcie *pci) dw_pcie_dbi_ro_wr_dis(pci); } +static void rockchip_pcie_enable_debug(struct rockchip_pcie *rockchip) +{ + rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DBG_TRANSITION_DATA, + PCIE_CLIENT_DBG_FIFO_PTN_HIT_D0); + rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DBG_TRANSITION_DATA, + PCIE_CLIENT_DBG_FIFO_PTN_HIT_D1); + rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DBG_TRANSITION_DATA, + PCIE_CLIENT_DBG_FIFO_TRN_HIT_D0); + rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DBG_TRANSITION_DATA, + PCIE_CLIENT_DBG_FIFO_TRN_HIT_D1); + rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_DBF_EN, + PCIE_CLIENT_DBG_FIFO_MODE_CON); +} + +static void rockchip_pcie_debug_dump(struct rockchip_pcie *rockchip) +{ +#if RK_PCIE_DBG + u32 loop; + + dev_info(rockchip->pci.dev, "ltssm = 0x%x\n", + rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS)); + for (loop = 0; loop < 64; loop++) + dev_info(rockchip->pci.dev, "fifo_status = 0x%x\n", + rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_DBG_FIFO_STATUS)); +#endif +} + static int rockchip_pcie_config_host(struct rockchip_pcie *rockchip) { struct device *dev = rockchip->pci.dev; struct dw_pcie *pci = &rockchip->pci; u32 reg, val; - int ret, retry, i; + int ret, retries, i; /* Detecting ATU features to achieve DWC ATU interface development */ dw_pcie_iatu_detect(&rockchip->pci); @@ -810,8 +939,10 @@ static int rockchip_pcie_config_host(struct rockchip_pcie *rockchip) dev_info(dev, "hot reset ever\n"); } rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); + rockchip_pcie_enable_debug(rockchip); - for (retry = 0; retry < 1000; retry++) { + retries = 1000; + for (i = 0; i < retries; i++) { if (dw_pcie_link_up(&rockchip->pci)) { /* * We may be here in case of L0 in Gen1. But if EP is capable @@ -820,18 +951,23 @@ static int rockchip_pcie_config_host(struct rockchip_pcie *rockchip) * that LTSSM max timeout is 24ms per period, we can wait a bit * more for Gen switch. */ - msleep(2000); - dev_info(dev, "PCIe Link up, LTSSM is 0x%x\n", - rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS)); - break; + msleep(50); + /* In case link drop after linkup, double check it */ + if (dw_pcie_link_up(pci)) { + dev_info(pci->dev, "PCIe Link up, LTSSM is 0x%x\n", + rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS)); + rockchip_pcie_debug_dump(rockchip); + break; + } } dev_info_ratelimited(dev, "PCIe Linking... LTSSM is 0x%x\n", rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_LTSSM_STATUS)); + rockchip_pcie_debug_dump(rockchip); msleep(20); } - if (retry >= 10000) { + if (i >= retries) { ret = -ENODEV; return ret; } @@ -1153,6 +1289,13 @@ static int pcie_ep_mmap(struct file *file, struct vm_area_struct *vma) } addr = rockchip->ib_target_address[0]; break; + case PCIE_EP_MMAP_RESOURCE_BAR1: + if (size > rockchip->ib_target_size[1]) { + dev_warn(rockchip->pci.dev, "bar1 mmap size is out of limitation\n"); + return -EINVAL; + } + addr = rockchip->ib_target_address[1]; + break; case PCIE_EP_MMAP_RESOURCE_BAR2: if (size > rockchip->ib_target_size[2]) { dev_warn(rockchip->pci.dev, "bar2 mmap size is out of limitation\n"); @@ -1160,6 +1303,13 @@ static int pcie_ep_mmap(struct file *file, struct vm_area_struct *vma) } addr = rockchip->ib_target_address[2]; break; + case PCIE_EP_MMAP_RESOURCE_BAR5: + if (size > rockchip->ib_target_size[5]) { + dev_warn(rockchip->pci.dev, "bar5 mmap size is out of limitation\n"); + return -EINVAL; + } + addr = rockchip->ib_target_address[5]; + break; default: dev_err(rockchip->pci.dev, "cur mmap_res %d is unsurreport\n", rockchip->cur_mmap_res); return -EINVAL; @@ -1265,11 +1415,54 @@ deinit_host: return ret; } +static int __maybe_unused rockchip_dw_pcie_suspend(struct device *dev) +{ + struct rockchip_pcie *rockchip = dev_get_drvdata(dev); + + rockchip_pcie_deinit_host(rockchip); + + return 0; +} + +static int __maybe_unused rockchip_dw_pcie_resume(struct device *dev) +{ + struct rockchip_pcie *rockchip = dev_get_drvdata(dev); + int ret; + + ret = rockchip_pcie_init_host(rockchip); + if (ret) { + dev_err(dev, "Failed to init host!\n"); + return ret; + } + + ret = rockchip_pcie_config_host(rockchip); + if (ret) { + dev_err(dev, "Failed to config host!\n"); + goto deinit_host; + } + + gpiod_set_value_cansleep(rockchip->wake_gpio, 0); + usleep_range(PCIE_WAKE_DELAY_US, PCIE_WAKE_DELAY_US + 500); + gpiod_set_value_cansleep(rockchip->wake_gpio, 1); + + return ret; +deinit_host: + rockchip_pcie_deinit_host(rockchip); + + return ret; +} + +static const struct dev_pm_ops rockchip_dw_pcie_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rockchip_dw_pcie_suspend, + rockchip_dw_pcie_resume) +}; + static struct platform_driver rk_plat_pcie_driver = { .driver = { .name = "rk-pcie-ep", .of_match_table = rockchip_pcie_ep_of_match, .suppress_bind_attrs = true, + .pm = &rockchip_dw_pcie_pm_ops, }, .probe = rockchip_pcie_ep_probe, }; diff --git a/drivers/video/rockchip/rga3/include/rga_dma_buf.h b/drivers/video/rockchip/rga3/include/rga_dma_buf.h index fefea23914e2..05a801c0705c 100644 --- a/drivers/video/rockchip/rga3/include/rga_dma_buf.h +++ b/drivers/video/rockchip/rga3/include/rga_dma_buf.h @@ -26,18 +26,18 @@ int rga_buf_size_cal(unsigned long yrgb_addr, unsigned long uv_addr, int rga_virtual_memory_check(void *vaddr, u32 w, u32 h, u32 format, int fd); int rga_dma_memory_check(struct rga_dma_buffer *rga_dma_buffer, struct rga_img_info_t *img); -int rga_iommu_map_sgt(struct sg_table *sgt, size_t size, - struct rga_dma_buffer *buffer, - struct device *rga_dev); -int rga_iommu_map(phys_addr_t paddr, size_t size, - struct rga_dma_buffer *buffer, - struct device *rga_dev); -void rga_iommu_unmap(struct rga_dma_buffer *buffer); +int rga_dma_map_phys_addr(phys_addr_t phys_addr, size_t size, struct rga_dma_buffer *buffer, + enum dma_data_direction dir, struct device *map_dev); +void rga_dma_unmap_phys_addr(struct rga_dma_buffer *buffer); + +int rga_dma_map_sgt(struct sg_table *sgt, struct rga_dma_buffer *buffer, + enum dma_data_direction dir, struct device *map_dev); +void rga_dma_unmap_sgt(struct rga_dma_buffer *buffer); int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buffer, - enum dma_data_direction dir, struct device *rga_dev); + enum dma_data_direction dir, struct device *map_dev); int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer, - enum dma_data_direction dir, struct device *rga_dev); + enum dma_data_direction dir, struct device *map_dev); void rga_dma_unmap_buf(struct rga_dma_buffer *rga_dma_buffer); void rga_dma_sync_flush_range(void *pstart, void *pend, struct rga_scheduler_t *scheduler); diff --git a/drivers/video/rockchip/rga3/include/rga_drv.h b/drivers/video/rockchip/rga3/include/rga_drv.h index f934e38c6a83..0d41d4be2e8a 100644 --- a/drivers/video/rockchip/rga3/include/rga_drv.h +++ b/drivers/video/rockchip/rga3/include/rga_drv.h @@ -182,8 +182,11 @@ struct rga_dma_buffer { */ size_t offset; - /* The scheduler of the mapping */ - struct rga_scheduler_t *scheduler; + /* + * The device used by dma-buf mapping, which usually corresponds to the + * default domain or the current device. + */ + struct device *map_dev; }; struct rga_virt_addr { @@ -192,6 +195,7 @@ struct rga_virt_addr { struct page **pages; int pages_order; int page_count; + /* Actual effective size */ unsigned long size; /* The offset of the first page of the virtual address */ @@ -227,6 +231,9 @@ struct rga_internal_buffer { struct kref refcount; struct rga_session *session; + + /* The scheduler of the mapping */ + struct rga_scheduler_t *scheduler; }; struct rga_scheduler_t; diff --git a/drivers/video/rockchip/rga3/include/rga_mm.h b/drivers/video/rockchip/rga3/include/rga_mm.h index d68fd75dcb45..a75f2470b928 100644 --- a/drivers/video/rockchip/rga3/include/rga_mm.h +++ b/drivers/video/rockchip/rga3/include/rga_mm.h @@ -42,7 +42,7 @@ static inline bool rga_mm_is_invalid_dma_buffer(struct rga_dma_buffer *buffer) if (buffer == NULL) return true; - return buffer->scheduler == NULL ? true : false; + return buffer->map_dev == NULL ? true : false; } struct rga_internal_buffer *rga_mm_lookup_handle(struct rga_mm *mm_session, uint32_t handle); diff --git a/drivers/video/rockchip/rga3/rga_debugger.c b/drivers/video/rockchip/rga3/rga_debugger.c index 93c5fcf3ec48..572035977338 100644 --- a/drivers/video/rockchip/rga3/rga_debugger.c +++ b/drivers/video/rockchip/rga3/rga_debugger.c @@ -286,7 +286,7 @@ static int rga_mm_session_show(struct seq_file *m, void *data) (unsigned long)dump_buffer->dma_buffer->iova, dump_buffer->dma_buffer->sgt, dump_buffer->dma_buffer->size, - dump_buffer->dma_buffer->scheduler->core); + dump_buffer->scheduler->core); if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) seq_printf(m, "\t is contiguous, pa = 0x%lx\n", @@ -310,7 +310,7 @@ static int rga_mm_session_show(struct seq_file *m, void *data) (unsigned long)dump_buffer->dma_buffer->offset, dump_buffer->dma_buffer->sgt, dump_buffer->dma_buffer->size, - dump_buffer->dma_buffer->scheduler->core); + dump_buffer->scheduler->core); if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) seq_printf(m, "\t is contiguous, pa = 0x%lx\n", diff --git a/drivers/video/rockchip/rga3/rga_dma_buf.c b/drivers/video/rockchip/rga3/rga_dma_buf.c index e72470e5c5f5..96609d0784fe 100644 --- a/drivers/video/rockchip/rga3/rga_dma_buf.c +++ b/drivers/video/rockchip/rga3/rga_dma_buf.c @@ -11,20 +11,6 @@ #include "rga_job.h" #include "rga_debugger.h" -static int rga_dma_info_to_prot(enum dma_data_direction dir) -{ - switch (dir) { - case DMA_BIDIRECTIONAL: - return IOMMU_READ | IOMMU_WRITE; - case DMA_TO_DEVICE: - return IOMMU_READ; - case DMA_FROM_DEVICE: - return IOMMU_WRITE; - default: - return 0; - } -} - int rga_buf_size_cal(unsigned long yrgb_addr, unsigned long uv_addr, unsigned long v_addr, int format, uint32_t w, uint32_t h, unsigned long *StartAddr, unsigned long *size) @@ -198,165 +184,6 @@ int rga_buf_size_cal(unsigned long yrgb_addr, unsigned long uv_addr, return pageCount; } -static dma_addr_t rga_iommu_dma_alloc_iova(struct iommu_domain *domain, - size_t size, u64 dma_limit, - struct device *dev) -{ - struct rga_iommu_dma_cookie *cookie = (void *)domain->iova_cookie; - struct iova_domain *iovad = &cookie->iovad; - unsigned long shift, iova_len, iova = 0; - - shift = iova_shift(iovad); - iova_len = size >> shift; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0)) - /* - * Freeing non-power-of-two-sized allocations back into the IOVA caches - * will come back to bite us badly, so we have to waste a bit of space - * rounding up anything cacheable to make sure that can't happen. The - * order of the unadjusted size will still match upon freeing. - */ - if (iova_len < (1 << (IOVA_RANGE_CACHE_MAX_SIZE - 1))) - iova_len = roundup_pow_of_two(iova_len); -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) - dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit); -#else - if (dev->bus_dma_mask) - dma_limit &= dev->bus_dma_mask; -#endif - - if (domain->geometry.force_aperture) - dma_limit = min(dma_limit, (u64)domain->geometry.aperture_end); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(4, 19, 111) && \ - LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) - iova = alloc_iova_fast(iovad, iova_len, - min_t(dma_addr_t, dma_limit >> shift, iovad->end_pfn), - true); -#else - iova = alloc_iova_fast(iovad, iova_len, dma_limit >> shift, true); -#endif - - return (dma_addr_t)iova << shift; -} - -static void rga_iommu_dma_free_iova(struct iommu_domain *domain, - dma_addr_t iova, size_t size) -{ - struct rga_iommu_dma_cookie *cookie = (void *)domain->iova_cookie; - struct iova_domain *iovad = &cookie->iovad; - - free_iova_fast(iovad, iova_pfn(iovad, iova), size >> iova_shift(iovad)); -} - -static inline struct iommu_domain *rga_iommu_get_dma_domain(struct device *dev) -{ - return iommu_get_domain_for_dev(dev); -} - -void rga_iommu_unmap(struct rga_dma_buffer *buffer) -{ - if (buffer == NULL) - return; - if (buffer->iova == 0) - return; - - iommu_unmap(buffer->domain, buffer->iova, buffer->size); - rga_iommu_dma_free_iova(buffer->domain, buffer->iova, buffer->size); -} - -int rga_iommu_map_sgt(struct sg_table *sgt, size_t size, - struct rga_dma_buffer *buffer, - struct device *rga_dev) -{ - struct iommu_domain *domain = NULL; - struct rga_iommu_dma_cookie *cookie; - struct iova_domain *iovad; - dma_addr_t iova; - size_t map_size; - unsigned long align_size; - - if (sgt == NULL) { - rga_err("can not map iommu, because sgt is null!\n"); - return -EINVAL; - } - - domain = rga_iommu_get_dma_domain(rga_dev); - cookie = (void *)domain->iova_cookie; - iovad = &cookie->iovad; - align_size = iova_align(iovad, size); - - if (DEBUGGER_EN(MSG)) - rga_log("iova_align size = %ld", align_size); - - iova = rga_iommu_dma_alloc_iova(domain, align_size, rga_dev->coherent_dma_mask, rga_dev); - if (!iova) { - rga_err("rga_iommu_dma_alloc_iova failed"); - return -ENOMEM; - } - - map_size = iommu_map_sg(domain, iova, sgt->sgl, sgt->orig_nents, - rga_dma_info_to_prot(DMA_BIDIRECTIONAL)); - if (map_size < align_size) { - rga_err("iommu can not map sgt to iova"); - rga_iommu_dma_free_iova(domain, iova, align_size); - return -EINVAL; - } - - buffer->domain = domain; - buffer->iova = iova; - buffer->size = align_size; - - return 0; -} - -int rga_iommu_map(phys_addr_t paddr, size_t size, - struct rga_dma_buffer *buffer, - struct device *rga_dev) -{ - int ret; - struct iommu_domain *domain = NULL; - struct rga_iommu_dma_cookie *cookie; - struct iova_domain *iovad; - dma_addr_t iova; - unsigned long align_size; - - if (paddr == 0) { - rga_err("can not map iommu, because phys_addr is 0!\n"); - return -EINVAL; - } - - domain = rga_iommu_get_dma_domain(rga_dev); - cookie = (void *)domain->iova_cookie; - iovad = &cookie->iovad; - align_size = iova_align(iovad, size); - - if (DEBUGGER_EN(MSG)) - rga_log("iova_align size = %ld", align_size); - - iova = rga_iommu_dma_alloc_iova(domain, align_size, rga_dev->coherent_dma_mask, rga_dev); - if (!iova) { - rga_err("rga_iommu_dma_alloc_iova failed"); - return -ENOMEM; - } - - ret = iommu_map(domain, iova, paddr, align_size, - rga_dma_info_to_prot(DMA_BIDIRECTIONAL)); - if (ret) { - rga_err("iommu can not map phys_addr to iova"); - rga_iommu_dma_free_iova(domain, iova, align_size); - return ret; - } - - buffer->domain = domain; - buffer->iova = iova; - buffer->size = align_size; - - return 0; -} - int rga_virtual_memory_check(void *vaddr, u32 w, u32 h, u32 format, int fd) { int bits = 32; @@ -424,8 +251,67 @@ int rga_dma_memory_check(struct rga_dma_buffer *rga_dma_buffer, struct rga_img_i return ret; } +int rga_dma_map_phys_addr(phys_addr_t phys_addr, size_t size, struct rga_dma_buffer *buffer, + enum dma_data_direction dir, struct device *map_dev) +{ + dma_addr_t addr; + + addr = dma_map_resource(map_dev, phys_addr, size, dir, 0); + if (addr == DMA_MAPPING_ERROR) { + rga_err("dma_map_resouce failed!\n"); + return -EINVAL; + } + + buffer->dma_addr = addr; + buffer->dir = dir; + buffer->size = size; + buffer->map_dev = map_dev; + + return 0; +} + +void rga_dma_unmap_phys_addr(struct rga_dma_buffer *buffer) +{ + dma_unmap_resource(buffer->map_dev, buffer->dma_addr, buffer->size, buffer->dir, 0); +} + +int rga_dma_map_sgt(struct sg_table *sgt, struct rga_dma_buffer *buffer, + enum dma_data_direction dir, struct device *map_dev) +{ + int i, ret = 0; + struct scatterlist *sg = NULL; + + ret = dma_map_sg(map_dev, sgt->sgl, sgt->orig_nents, dir); + if (ret <= 0) { + rga_err("dma_map_sg failed! ret = %d\n", ret); + return ret < 0 ? ret : -EINVAL; + } + sgt->nents = ret; + + buffer->sgt = sgt; + buffer->dma_addr = sg_dma_address(sgt->sgl); + buffer->dir = dir; + buffer->size = 0; + for_each_sgtable_sg(sgt, sg, i) + buffer->size += sg_dma_len(sg); + buffer->map_dev = map_dev; + + return 0; +} + +void rga_dma_unmap_sgt(struct rga_dma_buffer *buffer) +{ + if (!buffer->sgt) + return; + + dma_unmap_sg(buffer->map_dev, + buffer->sgt->sgl, + buffer->sgt->orig_nents, + buffer->dir); +} + int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buffer, - enum dma_data_direction dir, struct device *rga_dev) + enum dma_data_direction dir, struct device *map_dev) { struct dma_buf_attachment *attach = NULL; struct sg_table *sgt = NULL; @@ -439,7 +325,7 @@ int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buff return -EINVAL; } - attach = dma_buf_attach(dma_buf, rga_dev); + attach = dma_buf_attach(dma_buf, map_dev); if (IS_ERR(attach)) { ret = PTR_ERR(attach); rga_err("Failed to attach dma_buf, ret[%d]\n", ret); @@ -461,6 +347,7 @@ int rga_dma_map_buf(struct dma_buf *dma_buf, struct rga_dma_buffer *rga_dma_buff rga_dma_buffer->size = 0; for_each_sgtable_sg(sgt, sg, i) rga_dma_buffer->size += sg_dma_len(sg); + rga_dma_buffer->map_dev = map_dev; return ret; @@ -475,7 +362,7 @@ err_get_attach: } int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer, - enum dma_data_direction dir, struct device *rga_dev) + enum dma_data_direction dir, struct device *map_dev) { struct dma_buf *dma_buf = NULL; struct dma_buf_attachment *attach = NULL; @@ -490,7 +377,7 @@ int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer, return ret; } - attach = dma_buf_attach(dma_buf, rga_dev); + attach = dma_buf_attach(dma_buf, map_dev); if (IS_ERR(attach)) { ret = PTR_ERR(attach); rga_err("Failed to attach dma_buf, ret[%d]\n", ret); @@ -512,6 +399,7 @@ int rga_dma_map_fd(int fd, struct rga_dma_buffer *rga_dma_buffer, rga_dma_buffer->size = 0; for_each_sgtable_sg(sgt, sg, i) rga_dma_buffer->size += sg_dma_len(sg); + rga_dma_buffer->map_dev = map_dev; return ret; @@ -551,12 +439,12 @@ int rga_dma_free(struct rga_dma_buffer *buffer) return -EINVAL; } - dma_free_coherent(buffer->scheduler->dev, buffer->size, buffer->vaddr, buffer->dma_addr); + dma_free_coherent(buffer->map_dev, buffer->size, buffer->vaddr, buffer->dma_addr); buffer->vaddr = NULL; buffer->dma_addr = 0; buffer->iova = 0; buffer->size = 0; - buffer->scheduler = NULL; + buffer->map_dev = NULL; kfree(buffer); @@ -581,7 +469,7 @@ struct rga_dma_buffer *rga_dma_alloc_coherent(struct rga_scheduler_t *scheduler, buffer->size = align_size; buffer->dma_addr = dma_addr; - buffer->scheduler = scheduler; + buffer->map_dev = scheduler->dev; if (scheduler->data->mmu == RGA_IOMMU) buffer->iova = buffer->dma_addr; diff --git a/drivers/video/rockchip/rga3/rga_mm.c b/drivers/video/rockchip/rga3/rga_mm.c index 12b3342c0b67..eb34fde9d769 100644 --- a/drivers/video/rockchip/rga3/rga_mm.c +++ b/drivers/video/rockchip/rga3/rga_mm.c @@ -179,11 +179,10 @@ static struct sg_table *rga_alloc_sgt(struct rga_virt_addr *virt_addr) } /* get sg form pages. */ - /* iova requires minimum page alignment, so sgt cannot have offset */ ret = sg_alloc_table_from_pages(sgt, virt_addr->pages, virt_addr->page_count, - 0, + virt_addr->offset, virt_addr->size, GFP_KERNEL); if (ret) { @@ -232,7 +231,6 @@ static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p, unsigned int count; int img_size; size_t offset; - unsigned long size; struct page **pages = NULL; struct rga_virt_addr *virt_addr = NULL; @@ -246,10 +244,9 @@ static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p, offset = viraddr & (~PAGE_MASK); count = RGA_GET_PAGE_COUNT(img_size + offset); - size = count * PAGE_SIZE; - if (!size) { - rga_err("failed to calculating buffer size! size = %ld, count = %d, offset = %ld\n", - size, count, (unsigned long)offset); + if (!count) { + rga_err("failed to calculating buffer size! img_size = %d, count = %d, offset = %ld\n", + img_size, count, (unsigned long)offset); rga_dump_memory_parm(memory_parm); return -EFAULT; } @@ -292,7 +289,7 @@ static int rga_alloc_virt_addr(struct rga_virt_addr **virt_addr_p, virt_addr->pages = pages; virt_addr->pages_order = order; virt_addr->page_count = count; - virt_addr->size = size; + virt_addr->size = img_size; virt_addr->offset = offset; virt_addr->result = result; @@ -398,18 +395,17 @@ static int rga_mm_map_dma_buffer(struct rga_external_buffer *external_buffer, return ex_buffer_size == 0 ? -EINVAL : ex_buffer_size; } - /* - * dma-buf api needs to use default_domain of main dev, - * and not IOMMU for devices without iommu_info ptr. - */ - map_dev = scheduler->iommu_info ? scheduler->iommu_info->default_dev : scheduler->dev; - buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); if (buffer == NULL) { rga_err("%s alloc internal_buffer error!\n", __func__); return -ENOMEM; } + /* + * dma-buf api needs to use default_domain of main dev, + * and not IOMMU for devices without iommu_info ptr. + */ + map_dev = scheduler->iommu_info ? scheduler->iommu_info->default_dev : scheduler->dev; switch (external_buffer->type) { case RGA_DMA_BUFFER: ret = rga_dma_map_fd((int)external_buffer->memory, @@ -440,8 +436,6 @@ static int rga_mm_map_dma_buffer(struct rga_external_buffer *external_buffer, goto unmap_buffer; } - buffer->scheduler = scheduler; - if (scheduler->data->mmu == RGA_IOMMU) buffer->iova = buffer->dma_addr; @@ -473,6 +467,8 @@ static int rga_mm_map_dma_buffer(struct rga_external_buffer *external_buffer, internal_buffer->dma_buffer = buffer; internal_buffer->mm_flag = mm_flag; internal_buffer->phys_addr = phys_addr ? phys_addr : 0; + internal_buffer->size = buffer->size - buffer->offset; + internal_buffer->scheduler = scheduler; return 0; @@ -492,19 +488,7 @@ static void rga_mm_unmap_virt_addr(struct rga_internal_buffer *internal_buffer) if (rga_mm_is_invalid_dma_buffer(internal_buffer->dma_buffer)) return; - switch (internal_buffer->dma_buffer->scheduler->data->mmu) { - case RGA_IOMMU: - rga_iommu_unmap(internal_buffer->dma_buffer); - break; - case RGA_MMU: - dma_unmap_sg(internal_buffer->dma_buffer->scheduler->dev, - internal_buffer->dma_buffer->sgt->sgl, - internal_buffer->dma_buffer->sgt->orig_nents, - DMA_BIDIRECTIONAL); - break; - default: - break; - } + rga_dma_unmap_sgt(internal_buffer->dma_buffer); if (internal_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS && internal_buffer->phys_addr > 0) @@ -532,6 +516,7 @@ static int rga_mm_map_virt_addr(struct rga_external_buffer *external_buffer, struct sg_table *sgt; struct rga_virt_addr *virt_addr; struct rga_dma_buffer *buffer; + struct device *map_dev; struct rga_scheduler_t *scheduler; scheduler = job ? job->scheduler : @@ -578,6 +563,11 @@ static int rga_mm_map_virt_addr(struct rga_external_buffer *external_buffer, } mm_flag |= RGA_MEM_PHYSICAL_CONTIGUOUS; + } else if (scheduler->data->mmu == RGA_NONE_MMU) { + rga_err("Current %s[%d] cannot support physically discontinuous virtual address!\n", + rga_get_mmu_type_str(scheduler->data->mmu), scheduler->data->mmu); + ret = -EOPNOTSUPP; + goto free_sgt; } /* @@ -601,47 +591,28 @@ static int rga_mm_map_virt_addr(struct rga_external_buffer *external_buffer, goto free_sgt; } - switch (scheduler->data->mmu) { - case RGA_IOMMU: - ret = rga_iommu_map_sgt(sgt, virt_addr->size, buffer, scheduler->dev); - if (ret < 0) { - rga_err("%s core[%d] iommu_map virtual address error!\n", - __func__, scheduler->core); - goto free_dma_buffer; - } - - buffer->dma_addr = buffer->iova; - - break; - case RGA_MMU: - ret = dma_map_sg(scheduler->dev, sgt->sgl, sgt->orig_nents, DMA_BIDIRECTIONAL); - if (ret == 0) { - rga_err("%s core[%d] dma_map_sgt error! va = 0x%lx, nents = %d\n", - __func__, scheduler->core, - (unsigned long)virt_addr->addr, sgt->orig_nents); - ret = -EINVAL; - goto free_dma_buffer; - } - break; - default: - if (mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) - break; - - rga_err("Current %s[%d] cannot support physically discontinuous virtual address!\n", - rga_get_mmu_type_str(scheduler->data->mmu), scheduler->data->mmu); - ret = -EOPNOTSUPP; + /* + * dma-buf api needs to use default_domain of main dev, + * and not IOMMU for devices without iommu_info ptr. + */ + map_dev = scheduler->iommu_info ? scheduler->iommu_info->default_dev : scheduler->dev; + ret = rga_dma_map_sgt(sgt, buffer, DMA_BIDIRECTIONAL, map_dev); + if (ret < 0) { + rga_err("%s core[%d] rga map sgt failed! va = 0x%lx, orig_nents = %d\n", + __func__, scheduler->core, + (unsigned long)virt_addr->addr, sgt->orig_nents); goto free_dma_buffer; } - buffer->sgt = sgt; - buffer->offset = virt_addr->offset; - buffer->size = virt_addr->size; - buffer->scheduler = scheduler; + if (scheduler->data->mmu == RGA_IOMMU) + buffer->iova = buffer->dma_addr; internal_buffer->virt_addr = virt_addr; internal_buffer->dma_buffer = buffer; internal_buffer->mm_flag = mm_flag; internal_buffer->phys_addr = phys_addr ? phys_addr + virt_addr->offset : 0; + internal_buffer->size = buffer->size - buffer->offset; + internal_buffer->scheduler = scheduler; return 0; @@ -661,16 +632,12 @@ put_current_mm: static void rga_mm_unmap_phys_addr(struct rga_internal_buffer *internal_buffer) { - WARN_ON(internal_buffer->dma_buffer == NULL); + if (internal_buffer->dma_buffer != NULL) { + rga_dma_unmap_phys_addr(internal_buffer->dma_buffer); + kfree(internal_buffer->dma_buffer); + internal_buffer->dma_buffer = NULL; + } - if (rga_mm_is_invalid_dma_buffer(internal_buffer->dma_buffer)) - return; - - if (internal_buffer->dma_buffer->scheduler->data->mmu == RGA_IOMMU) - rga_iommu_unmap(internal_buffer->dma_buffer); - - kfree(internal_buffer->dma_buffer); - internal_buffer->dma_buffer = NULL; internal_buffer->phys_addr = 0; internal_buffer->size = 0; } @@ -683,7 +650,8 @@ static int rga_mm_map_phys_addr(struct rga_external_buffer *external_buffer, phys_addr_t phys_addr; int buffer_size; uint32_t mm_flag = 0; - struct rga_dma_buffer *buffer; + struct rga_dma_buffer *buffer = NULL; + struct device *map_dev; struct rga_scheduler_t *scheduler; scheduler = job ? job->scheduler : @@ -717,26 +685,34 @@ static int rga_mm_map_phys_addr(struct rga_external_buffer *external_buffer, return -EINVAL; } - buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); - if (buffer == NULL) { - rga_err("%s alloc internal dma buffer error!\n", __func__); - return -ENOMEM; - } - if (scheduler->data->mmu == RGA_IOMMU) { - ret = rga_iommu_map(phys_addr, buffer_size, buffer, scheduler->dev); + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (buffer == NULL) { + rga_err("%s alloc internal dma buffer error!\n", __func__); + return -ENOMEM; + } + + /* + * dma-buf api needs to use default_domain of main dev, + * and not IOMMU for devices without iommu_info ptr. + */ + map_dev = scheduler->iommu_info ? + scheduler->iommu_info->default_dev : scheduler->dev; + ret = rga_dma_map_phys_addr(phys_addr, buffer_size, buffer, + DMA_BIDIRECTIONAL, map_dev); if (ret < 0) { rga_err("%s core[%d] map phys_addr error!\n", __func__, scheduler->core); goto free_dma_buffer; } + + buffer->iova = buffer->dma_addr; } - buffer->scheduler = scheduler; - - internal_buffer->phys_addr = phys_addr; - internal_buffer->size = buffer_size; - internal_buffer->mm_flag = mm_flag; internal_buffer->dma_buffer = buffer; + internal_buffer->mm_flag = mm_flag; + internal_buffer->phys_addr = phys_addr; + internal_buffer->size = buffer ? buffer->size : buffer_size; + internal_buffer->scheduler = scheduler; return 0; @@ -785,8 +761,6 @@ static int rga_mm_map_buffer(struct rga_external_buffer *external_buffer, if (ret < 0) return ret; - internal_buffer->size = internal_buffer->dma_buffer->size - - internal_buffer->dma_buffer->offset; internal_buffer->mm_flag |= RGA_MEM_NEED_USE_IOMMU; break; case RGA_VIRTUAL_ADDRESS: @@ -796,8 +770,6 @@ static int rga_mm_map_buffer(struct rga_external_buffer *external_buffer, if (ret < 0) return ret; - internal_buffer->size = internal_buffer->virt_addr->size - - internal_buffer->virt_addr->offset; internal_buffer->mm_flag |= RGA_MEM_NEED_USE_IOMMU; break; case RGA_PHYSICAL_ADDRESS: @@ -1002,7 +974,7 @@ void rga_mm_dump_buffer(struct rga_internal_buffer *dump_buffer) (unsigned long)dump_buffer->dma_buffer->offset, dump_buffer->dma_buffer->sgt, dump_buffer->dma_buffer->size, - dump_buffer->dma_buffer->scheduler->core); + dump_buffer->scheduler->core); if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) rga_log("is contiguous, pa = 0x%lx\n", @@ -1026,7 +998,7 @@ void rga_mm_dump_buffer(struct rga_internal_buffer *dump_buffer) (unsigned long)dump_buffer->dma_buffer->offset, dump_buffer->dma_buffer->sgt, dump_buffer->dma_buffer->size, - dump_buffer->dma_buffer->scheduler->core); + dump_buffer->scheduler->core); if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) rga_buf_log(dump_buffer, "is contiguous, pa = 0x%lx\n", @@ -1034,6 +1006,16 @@ void rga_mm_dump_buffer(struct rga_internal_buffer *dump_buffer) break; case RGA_PHYSICAL_ADDRESS: rga_buf_log(dump_buffer, "pa = 0x%lx\n", (unsigned long)dump_buffer->phys_addr); + + if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer)) + break; + + rga_buf_log(dump_buffer, "iova = 0x%lx, dma_addr = 0x%lx, offset = 0x%lx, size = %ld, map_core = 0x%x\n", + (unsigned long)dump_buffer->dma_buffer->iova, + (unsigned long)dump_buffer->dma_buffer->dma_addr, + (unsigned long)dump_buffer->dma_buffer->offset, + dump_buffer->dma_buffer->size, + dump_buffer->scheduler->core); break; default: rga_buf_err(dump_buffer, "Illegal buffer! type= %d\n", dump_buffer->type); @@ -1129,7 +1111,7 @@ static int rga_mm_sgt_to_page_table(struct sg_table *sg, * The length of each sgl is expected to be obtained here, not * the length of the entire dma_buf, so sg_dma_len() is not used. */ - len = sgl->length >> PAGE_SHIFT; + len = (sgl->length + (PAGE_SIZE - 1)) >> PAGE_SHIFT; if (use_dma_address) /* @@ -1148,6 +1130,8 @@ static int rga_mm_sgt_to_page_table(struct sg_table *sg, else Address = sg_phys(sgl); + Address &= PAGE_MASK; + for (i = 0; i < len; i++) { if (mapped_size + i >= pageCount) { break_flag = 1; @@ -1335,16 +1319,26 @@ static int rga_mm_sync_dma_sg_for_device(struct rga_internal_buffer *buffer, struct rga_scheduler_t *scheduler; ktime_t timestamp = ktime_get(); - scheduler = buffer->dma_buffer->scheduler; + scheduler = buffer->scheduler; if (scheduler == NULL) { rga_job_err(job, "%s(%d), failed to get scheduler, core = 0x%x\n", __func__, __LINE__, job->core); return -EFAULT; } - if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS && - scheduler->data->mmu != RGA_IOMMU) { - dma_sync_single_for_device(scheduler->dev, buffer->phys_addr, buffer->size, dir); + if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) { + if (scheduler->data->mmu == RGA_IOMMU) { + if (rga_mm_is_invalid_dma_buffer(buffer->dma_buffer)) { + rga_job_err(job, "invalid dma-buffer with IOMMU device!\n"); + return -EFAULT; + } + + dma_sync_single_for_device(buffer->dma_buffer->map_dev, + buffer->dma_buffer->iova, buffer->dma_buffer->size, dir); + } else { + dma_sync_single_for_device(scheduler->dev, + buffer->phys_addr, buffer->size, dir); + } } else { sgt = rga_mm_lookup_sgt(buffer); if (sgt == NULL) { @@ -1372,16 +1366,26 @@ static int rga_mm_sync_dma_sg_for_cpu(struct rga_internal_buffer *buffer, struct rga_scheduler_t *scheduler; ktime_t timestamp = ktime_get(); - scheduler = buffer->dma_buffer->scheduler; + scheduler = buffer->scheduler; if (scheduler == NULL) { rga_job_err(job, "%s(%d), failed to get scheduler, core = 0x%x\n", __func__, __LINE__, job->core); return -EFAULT; } - if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS && - scheduler->data->mmu != RGA_IOMMU) { - dma_sync_single_for_cpu(scheduler->dev, buffer->phys_addr, buffer->size, dir); + if (buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS) { + if (scheduler->data->mmu == RGA_IOMMU) { + if (rga_mm_is_invalid_dma_buffer(buffer->dma_buffer)) { + rga_job_err(job, "invalid dma-buffer with IOMMU device!\n"); + return -EFAULT; + } + + dma_sync_single_for_cpu(buffer->dma_buffer->map_dev, + buffer->dma_buffer->iova, buffer->dma_buffer->size, dir); + } else { + dma_sync_single_for_cpu(scheduler->dev, + buffer->phys_addr, buffer->size, dir); + } } else { sgt = rga_mm_lookup_sgt(buffer); if (sgt == NULL) { @@ -1920,6 +1924,8 @@ static int rga_mm_map_channel_job_buffer(struct rga_job *job, goto error_free_buffer; } + buffer->session = job->session; + if (DEBUGGER_EN(MM)) { rga_job_log(job, "map buffer:\n"); rga_mm_dump_buffer(buffer); diff --git a/include/uapi/linux/rk-pcie-ep.h b/include/uapi/linux/rk-pcie-ep.h index d89748eed925..64d83c0ab5c9 100644 --- a/include/uapi/linux/rk-pcie-ep.h +++ b/include/uapi/linux/rk-pcie-ep.h @@ -69,6 +69,8 @@ enum pcie_ep_mmap_resource { PCIE_EP_MMAP_RESOURCE_USER_MEM, PCIE_EP_MMAP_RESOURCE_RK3568_RC_DBI, PCIE_EP_MMAP_RESOURCE_RK3588_RC_DBI, + PCIE_EP_MMAP_RESOURCE_BAR1, + PCIE_EP_MMAP_RESOURCE_BAR5, PCIE_EP_MMAP_RESOURCE_MAX, };