RK3588平台maxim MIPI CSI VC虚拟通道支持不同分辨率

设备树

&i2c6 {
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&i2c6m3_xfer>;

	max96712_dphy3: max96712@29 {
		compatible = "maxim4c,max96712";
		status = "okay";
		reg = <0x29>;
		clock-names = "xvclk";
		clocks = <&max96712_dphy3_osc 0>;
		pinctrl-names = "default";
		pinctrl-0 = <&max96712_dphy3_errb>, <&max96712_dphy3_lock>;
		power-domains = <&power RK3588_PD_VI>;
		rockchip,grf = <&sys_grf>;
		vcc1v2-supply = <&max96712_dphy3_vcc1v2>;
		vcc1v8-supply = <&max96712_dphy3_vcc1v8>;
		pwdn-supply = <&max96712_dphy3_pwdn_regulator>;
		lock-gpios = <&gpio3 RK_PB4 GPIO_ACTIVE_HIGH>;

		rockchip,camera-module-index = <0>;
		rockchip,camera-module-facing = "back";
		rockchip,camera-module-name = "default";
		rockchip,camera-module-lens-name = "default";

		port {
			max96712_dphy3_out: endpoint {
				remote-endpoint = <&mipi_dphy3_in_max96712>;
				data-lanes = <1 2 3 4>;
			};
		};

		/* support mode config start */
		support-mode-config {
			status = "okay";

			bus-format = <MEDIA_BUS_FMT_UYVY8_2X8>;
			sensor-width = <1920>;
			sensor-height = <1440>;
			max-fps-numerator = <10000>;
			max-fps-denominator = <300000>;
			bpp = <16>;
			link-freq-idx = <20>;
			vc-info = <
					/* enable width height bus_fmt data_type data_bit */
					1 1920 1440 MEDIA_BUS_FMT_UYVY8_2X8 0 0 // vc0
					1 1920 1440 MEDIA_BUS_FMT_UYVY8_2X8 0 0 // vc1
					1 1920 1280 MEDIA_BUS_FMT_UYVY8_2X8 0 0 // vc2
					1 1920 1280 MEDIA_BUS_FMT_UYVY8_2X8 0 0 // vc3
			>;
		};

差分代码

From a1bcbccc82e2dbfeeb9ed64fc2bfdd80bcdab51e Mon Sep 17 00:00:00 2001
From: Cai Wenzhong <cwz@rock-chips.com>
Date: Tue, 11 Jun 2024 19:38:58 +0800
Subject: [PATCH] media: i2c: maxim: driver version v3.06.00

Signed-off-by: Cai Wenzhong <cwz@rock-chips.com>
Change-Id: If0c75766e3a8eaf6ad6921931c526454ca8b0511
---
 .../i2c/maxim/local/maxim2c/maxim2c_drv.c     |   7 +-
 .../i2c/maxim/local/maxim2c/maxim2c_drv.h     |  16 +++
 .../i2c/maxim/local/maxim2c/maxim2c_v4l2.c    | 106 +++++++++++++++++
 .../i2c/maxim/local/maxim4c/maxim4c_drv.c     |   7 +-
 .../i2c/maxim/local/maxim4c/maxim4c_drv.h     |  16 +++
 .../i2c/maxim/local/maxim4c/maxim4c_v4l2.c    | 107 ++++++++++++++++++
 6 files changed, 257 insertions(+), 2 deletions(-)

diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c
index 4588ce8edf41..ae4ebd53c28d 100644
--- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c
+++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c
@@ -47,6 +47,11 @@
  *     1. unified use __v4l2_ctrl_handler_setup in the xxx_start_stream
  *     2. support subscribe hot plug detect v4l2 event
  *
+ * V3.06.00
+ *     1. support multi-channel information configuration
+ *     2. mode vc initialization when vc-array isn't configured
+ *     3. fix the issue of mutex deadlock during hot plug
+ *
  */
 #include <linux/clk.h>
 #include <linux/i2c.h>
@@ -74,7 +79,7 @@
 
 #include "maxim2c_api.h"
 
-#define DRIVER_VERSION			KERNEL_VERSION(3, 0x05, 0x00)
+#define DRIVER_VERSION			KERNEL_VERSION(3, 0x06, 0x00)
 
 #define MAXIM2C_NAME			"maxim2c"
 
diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.h b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.h
index c7dc362bef75..b961cb0f0750 100644
--- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.h
+++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.h
@@ -49,6 +49,21 @@ struct maxim2c_hot_plug_work {
 	u32 hot_plug_state;
 };
 
+struct maxim2c_vc_info {
+	u32 enable; // 0: disable, !0: enable
+
+	u32 width;
+	u32 height;
+	u32 bus_fmt;
+
+	/*
+	 * the following are optional parameters, user-defined data types
+	 *   default 0: invalid parameter
+	 */
+	u32 data_type;
+	u32 data_bit;
+};
+
 struct maxim2c_mode {
 	u32 width;
 	u32 height;
@@ -61,6 +76,7 @@ struct maxim2c_mode {
 	u32 bpp;
 	const struct regval *reg_list;
 	u32 vc[PAD_MAX];
+	struct maxim2c_vc_info vc_info[PAD_MAX];
 	struct v4l2_rect crop_rect;
 };
 
diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c
index 00dbef3bd341..09f46e9db148 100644
--- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c
+++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c
@@ -103,6 +103,7 @@ static int maxim2c_support_mode_init(maxim2c_t *maxim2c)
 	struct device_node *node = NULL;
 	struct maxim2c_mode *mode = NULL;
 	u32 value = 0, vc_array[PAD_MAX], crop_array[4];
+	struct maxim2c_vc_info vc_info[PAD_MAX];
 	int ret = 0, i = 0, array_size = 0;
 
 	dev_info(dev, "=== maxim2c support mode init ===\n");
@@ -239,6 +240,41 @@ static int maxim2c_support_mode_init(maxim2c_t *maxim2c)
 	for (i = 0; i < PAD_MAX; i++)
 		dev_info(dev, "support mode: vc[%d] = 0x%x\n", i, mode->vc[i]);
 
+	/* vc info */
+	array_size = of_property_count_u32_elems(node, "vc-info");
+	if ((array_size > 0) &&
+			(array_size % sizeof(struct maxim2c_vc_info) == 0) &&
+			(array_size <= sizeof(struct maxim2c_vc_info) * PAD_MAX)) {
+
+		memset((char *)vc_info, 0, sizeof(vc_info));
+
+		ret = of_property_read_u32_array(node, "vc-info", (u32 *)vc_info, array_size);
+		if (ret == 0) {
+			/* <enable width height bus_fmt data_type data_bit> */
+			for (i = 0; i < PAD_MAX; i++) {
+				dev_info(dev, "vc-info[%d] property:\n", i);
+				dev_info(dev, "    vc-info[%d].enable = %d:\n", i, vc_info[i].enable);
+
+				dev_info(dev, "    vc-info[%d].width = %d:\n", i, vc_info[i].width);
+				dev_info(dev, "    vc-info[%d].height = %d:\n", i, vc_info[i].height);
+				dev_info(dev, "    vc-info[%d].bus_fmt = %d:\n", i, vc_info[i].bus_fmt);
+
+				dev_info(dev, "    vc-info[%d].data_type = %d:\n", i, vc_info[i].data_type);
+				dev_info(dev, "    vc-info[%d].data_bit = %d:\n", i, vc_info[i].data_bit);
+
+				mode->vc_info[i].enable = vc_info[i].enable;
+
+				mode->vc_info[i].width = vc_info[i].width;
+				mode->vc_info[i].height = vc_info[i].height;
+				mode->vc_info[i].bus_fmt = vc_info[i].bus_fmt;
+
+				mode->vc_info[i].data_type = vc_info[i].data_type;
+				mode->vc_info[i].data_bit = vc_info[i].data_bit;
+
+			}
+		}
+	}
+
 	/* crop rect */
 	array_size = of_property_read_variable_u32_array(node,
 				"crop-rect", crop_array, 1, 4);
@@ -354,11 +390,52 @@ static void maxim2c_set_vicap_rst_inf(maxim2c_t *maxim2c,
 	maxim2c->is_reset = rst_info.is_reset;
 }
 
+static int maxim2c_get_channel_info(maxim2c_t *maxim2c, struct rkmodule_channel_info *ch_info)
+{
+	const struct maxim2c_mode *mode = maxim2c->cur_mode;
+	struct device *dev = &maxim2c->client->dev;
+
+	if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX)
+		return -EINVAL;
+
+	if (mode->vc_info[ch_info->index].enable) {
+		ch_info->vc = mode->vc[ch_info->index];
+
+		ch_info->width = mode->vc_info[ch_info->index].width;
+		ch_info->height = mode->vc_info[ch_info->index].height;
+		ch_info->bus_fmt = mode->vc_info[ch_info->index].bus_fmt;
+
+		/* optional parameters, default 0: invalid parameter */
+		ch_info->data_type = mode->vc_info[ch_info->index].data_type;
+		ch_info->data_bit = mode->vc_info[ch_info->index].data_bit;
+	} else {
+		ch_info->vc = mode->vc[ch_info->index];
+
+		ch_info->width = mode->width;
+		ch_info->height = mode->height;
+		ch_info->bus_fmt = mode->bus_fmt;
+	}
+
+	dev_info(dev, "get channel info, ch_info->index = %d\n", ch_info->index);
+
+	dev_info(dev, "    ch_info->vc = 0x%x\n", ch_info->vc);
+
+	dev_info(dev, "    ch_info->width = %d\n", ch_info->width);
+	dev_info(dev, "    ch_info->height = %d\n", ch_info->height);
+	dev_info(dev, "    ch_info->bus_fmt = 0x%x\n", ch_info->bus_fmt);
+
+	dev_info(dev, "    ch_info->data_type = 0x%x:\n", ch_info->data_type);
+	dev_info(dev, "    ch_info->data_bit = %d\n", ch_info->data_bit);
+
+	return 0;
+}
+
 static long maxim2c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	maxim2c_t *maxim2c = v4l2_get_subdevdata(sd);
 	struct rkmodule_csi_dphy_param *dphy_param;
 	struct rkmodule_capture_info *capture_info;
+	struct rkmodule_channel_info *ch_info;
 	long ret = 0;
 
 	dev_dbg(&maxim2c->client->dev, "ioctl cmd = 0x%08x\n", cmd);
@@ -392,6 +469,10 @@ static long maxim2c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 		else
 			capture_info->mode = RKMODULE_CAPTURE_MODE_NONE;
 		break;
+	case RKMODULE_GET_CHANNEL_INFO:
+		ch_info = (struct rkmodule_channel_info *)arg;
+		ret = maxim2c_get_channel_info(maxim2c, ch_info);
+		break;
 	default:
 		ret = -ENOIOCTLCMD;
 		break;
@@ -409,6 +490,7 @@ static long maxim2c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd,
 	struct rkmodule_vicap_reset_info *vicap_rst_inf;
 	struct rkmodule_csi_dphy_param *dphy_param;
 	struct rkmodule_capture_info  *capture_info;
+	struct rkmodule_channel_info *ch_info;
 	long ret = 0;
 
 	switch (cmd) {
@@ -501,6 +583,21 @@ static long maxim2c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd,
 		}
 		kfree(capture_info);
 		break;
+	case RKMODULE_GET_CHANNEL_INFO:
+		ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
+		if (!ch_info) {
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		ret = maxim2c_ioctl(sd, cmd, ch_info);
+		if (!ret) {
+			ret = copy_to_user(up, ch_info, sizeof(*ch_info));
+			if (ret)
+				ret = -EFAULT;
+		}
+		kfree(ch_info);
+		break;
 	default:
 		ret = -ENOIOCTLCMD;
 		break;
@@ -914,8 +1011,17 @@ static int maxim2c_get_selection(struct v4l2_subdev *sd,
 #endif
 {
 	maxim2c_t *maxim2c = v4l2_get_subdevdata(sd);
+	int i = 0;
 
 	if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) {
+		/* if multiple channel info enable, get_selection isn't support */
+		for (i = 0; i < PAD_MAX; i++) {
+			if (maxim2c->cur_mode->vc_info[i].enable) {
+				v4l2_warn(sd, "Multi-channel enable, get_selection isn't support\n");
+				return -EINVAL;
+			}
+		}
+
 		sel->r.left = maxim2c->cur_mode->crop_rect.left;
 		sel->r.width = maxim2c->cur_mode->crop_rect.width;
 		sel->r.top = maxim2c->cur_mode->crop_rect.top;
diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c
index dcfb335a487b..11a2c49324d8 100644
--- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c
+++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c
@@ -70,6 +70,11 @@
  *     1. unified use __v4l2_ctrl_handler_setup in the xxx_start_stream
  *     2. support subscribe hot plug detect v4l2 event
  *
+ * V3.06.00
+ *     1. support multi-channel information configuration
+ *     2. mode vc initialization when vc-array isn't configured
+ *     3. fix the issue of mutex deadlock during hot plug
+ *
  */
 #include <linux/clk.h>
 #include <linux/i2c.h>
@@ -97,7 +102,7 @@
 
 #include "maxim4c_api.h"
 
-#define DRIVER_VERSION			KERNEL_VERSION(3, 0x05, 0x00)
+#define DRIVER_VERSION			KERNEL_VERSION(3, 0x06, 0x00)
 
 #define MAXIM4C_NAME			"maxim4c"
 
diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.h b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.h
index 2ecea27f22bd..18ec7828d0f7 100644
--- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.h
+++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.h
@@ -49,6 +49,21 @@ struct maxim4c_hot_plug_work {
 	u32 hot_plug_state;
 };
 
+struct maxim4c_vc_info {
+	u32 enable; // 0: disable, !0: enable
+
+	u32 width;
+	u32 height;
+	u32 bus_fmt;
+
+	/*
+	 * the following are optional parameters, user-defined data types
+	 *   default 0: invalid parameter
+	 */
+	u32 data_type;
+	u32 data_bit;
+};
+
 struct maxim4c_mode {
 	u32 width;
 	u32 height;
@@ -61,6 +76,7 @@ struct maxim4c_mode {
 	u32 bpp;
 	const struct regval *reg_list;
 	u32 vc[PAD_MAX];
+	struct maxim4c_vc_info vc_info[PAD_MAX];
 	struct v4l2_rect crop_rect;
 };
 
diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c
index 583a09af8d71..c0906470039b 100644
--- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c
+++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c
@@ -103,6 +103,7 @@ static int maxim4c_support_mode_init(maxim4c_t *maxim4c)
 	struct device_node *node = NULL;
 	struct maxim4c_mode *mode = NULL;
 	u32 value = 0, vc_array[PAD_MAX], crop_array[4];
+	struct maxim4c_vc_info vc_info[PAD_MAX];
 	int ret = 0, i = 0, array_size = 0;
 
 	dev_info(dev, "=== maxim4c support mode init ===\n");
@@ -239,6 +240,41 @@ static int maxim4c_support_mode_init(maxim4c_t *maxim4c)
 	for (i = 0; i < PAD_MAX; i++)
 		dev_info(dev, "support mode: vc[%d] = 0x%x\n", i, mode->vc[i]);
 
+	/* vc info */
+	array_size = of_property_count_u32_elems(node, "vc-info");
+	if ((array_size > 0) &&
+			(array_size % sizeof(struct maxim4c_vc_info) == 0) &&
+			(array_size <= sizeof(struct maxim4c_vc_info) * PAD_MAX)) {
+
+		memset((char *)vc_info, 0, sizeof(vc_info));
+
+		ret = of_property_read_u32_array(node, "vc-info", (u32 *)vc_info, array_size);
+		if (ret == 0) {
+			/* <enable width height bus_fmt data_type data_bit> */
+			for (i = 0; i < PAD_MAX; i++) {
+				dev_info(dev, "vc-info[%d] property:\n", i);
+				dev_info(dev, "    vc-info[%d].enable = %d:\n", i, vc_info[i].enable);
+
+				dev_info(dev, "    vc-info[%d].width = %d:\n", i, vc_info[i].width);
+				dev_info(dev, "    vc-info[%d].height = %d:\n", i, vc_info[i].height);
+				dev_info(dev, "    vc-info[%d].bus_fmt = %d:\n", i, vc_info[i].bus_fmt);
+
+				dev_info(dev, "    vc-info[%d].data_type = %d:\n", i, vc_info[i].data_type);
+				dev_info(dev, "    vc-info[%d].data_bit = %d:\n", i, vc_info[i].data_bit);
+
+				mode->vc_info[i].enable = vc_info[i].enable;
+
+				mode->vc_info[i].width = vc_info[i].width;
+				mode->vc_info[i].height = vc_info[i].height;
+				mode->vc_info[i].bus_fmt = vc_info[i].bus_fmt;
+
+				mode->vc_info[i].data_type = vc_info[i].data_type;
+				mode->vc_info[i].data_bit = vc_info[i].data_bit;
+
+			}
+		}
+	}
+
 	/* crop rect */
 	array_size = of_property_read_variable_u32_array(node,
 				"crop-rect", crop_array, 1, 4);
@@ -354,11 +390,52 @@ static void maxim4c_set_vicap_rst_inf(maxim4c_t *maxim4c,
 	maxim4c->is_reset = rst_info.is_reset;
 }
 
+static int maxim4c_get_channel_info(maxim4c_t *maxim4c, struct rkmodule_channel_info *ch_info)
+{
+	const struct maxim4c_mode *mode = maxim4c->cur_mode;
+	struct device *dev = &maxim4c->client->dev;
+
+	if (ch_info->index < PAD0 || ch_info->index >= PAD_MAX)
+		return -EINVAL;
+
+	if (mode->vc_info[ch_info->index].enable) {
+		ch_info->vc = mode->vc[ch_info->index];
+
+		ch_info->width = mode->vc_info[ch_info->index].width;
+		ch_info->height = mode->vc_info[ch_info->index].height;
+		ch_info->bus_fmt = mode->vc_info[ch_info->index].bus_fmt;
+
+		/* optional parameters, default 0: invalid parameter */
+		ch_info->data_type = mode->vc_info[ch_info->index].data_type;
+		ch_info->data_bit = mode->vc_info[ch_info->index].data_bit;
+	} else {
+		ch_info->vc = mode->vc[ch_info->index];
+
+		ch_info->width = mode->width;
+		ch_info->height = mode->height;
+		ch_info->bus_fmt = mode->bus_fmt;
+	}
+
+	dev_info(dev, "get channel info, ch_info->index = %d\n", ch_info->index);
+
+	dev_info(dev, "    ch_info->vc = 0x%x\n", ch_info->vc);
+
+	dev_info(dev, "    ch_info->width = %d\n", ch_info->width);
+	dev_info(dev, "    ch_info->height = %d\n", ch_info->height);
+	dev_info(dev, "    ch_info->bus_fmt = 0x%x\n", ch_info->bus_fmt);
+
+	dev_info(dev, "    ch_info->data_type = 0x%x:\n", ch_info->data_type);
+	dev_info(dev, "    ch_info->data_bit = %d\n", ch_info->data_bit);
+
+	return 0;
+}
+
 static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 {
 	maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
 	struct rkmodule_csi_dphy_param *dphy_param;
 	struct rkmodule_capture_info *capture_info;
+	struct rkmodule_channel_info *ch_info;
 	long ret = 0;
 
 	dev_dbg(&maxim4c->client->dev, "ioctl cmd = 0x%08x\n", cmd);
@@ -392,6 +469,10 @@ static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
 		else
 			capture_info->mode = RKMODULE_CAPTURE_MODE_NONE;
 		break;
+	case RKMODULE_GET_CHANNEL_INFO:
+		ch_info = (struct rkmodule_channel_info *)arg;
+		ret = maxim4c_get_channel_info(maxim4c, ch_info);
+		break;
 	default:
 		ret = -ENOIOCTLCMD;
 		break;
@@ -409,6 +490,7 @@ static long maxim4c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd,
 	struct rkmodule_vicap_reset_info *vicap_rst_inf;
 	struct rkmodule_csi_dphy_param *dphy_param;
 	struct rkmodule_capture_info  *capture_info;
+	struct rkmodule_channel_info *ch_info;
 	long ret = 0;
 
 	switch (cmd) {
@@ -501,6 +583,21 @@ static long maxim4c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd,
 		}
 		kfree(capture_info);
 		break;
+	case RKMODULE_GET_CHANNEL_INFO:
+		ch_info = kzalloc(sizeof(*ch_info), GFP_KERNEL);
+		if (!ch_info) {
+			ret = -ENOMEM;
+			return ret;
+		}
+
+		ret = maxim4c_ioctl(sd, cmd, ch_info);
+		if (!ret) {
+			ret = copy_to_user(up, ch_info, sizeof(*ch_info));
+			if (ret)
+				ret = -EFAULT;
+		}
+		kfree(ch_info);
+		break;
 	default:
 		ret = -ENOIOCTLCMD;
 		break;
@@ -914,8 +1011,18 @@ static int maxim4c_get_selection(struct v4l2_subdev *sd,
 #endif
 {
 	maxim4c_t *maxim4c = v4l2_get_subdevdata(sd);
+	int i = 0;
 
 	if (sel->target == V4L2_SEL_TGT_CROP_BOUNDS) {
+		/* if multiple channel info enable, get_selection isn't support */
+		for (i = 0; i < PAD_MAX; i++) {
+			if (maxim4c->cur_mode->vc_info[i].enable) {
+				v4l2_warn(sd,
+					"Multi-channel enable, get_selection isn't support\n");
+				return -EINVAL;
+			}
+		}
+
 		sel->r.left = maxim4c->cur_mode->crop_rect.left;
 		sel->r.width = maxim4c->cur_mode->crop_rect.width;
 		sel->r.top = maxim4c->cur_mode->crop_rect.top;
-- 
2.43.0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值