History

media: aspeed: Allow to capture from SoC display (GFX)

ASPEED BMC IC has 2 different display engines. Please find AST2600's datasheet to get detailed information. 1. VGA on PCIe 2. SoC Display (GFX) By default, video engine (VE) will capture video from VGA. This patch adds an option to capture video from GFX with standard ioctl, vidioc_s_input. An enum, aspeed_video_input, is added for this purpose. enum aspeed_video_input { VIDEO_INPUT_VGA = 0, VIDEO_INPUT_GFX, VIDEO_INPUT_MAX }; To test this feature, you will need to enable GFX first. Please refer to ASPEED's SDK_User_Guide, 6.3.x Soc Display driver, for more information. In your application, you will need to use v4l2 ioctl, VIDIOC_S_INPUT, as below to select before start streaming. int rc; struct v4l2_input input; input.index = VIDEO_INPUT_GFX; rc = ioctl(fd, VIDIOC_S_INPUT, &input); if (rc < 0) { ... }

Jammy Huang committed 1 year ago

Commit 039b9301 parent 98423792 files · +178 −28Browse files

Unified · Split

2 files
  1. drivers/media/platform/aspeed/aspeed-video.c +171 −28
  2. include/uapi/linux/aspeed-video.h +7 −0
drivers/media/platform/aspeed/aspeed-video.c+171−28
@@ -4,6 +4,7 @@ · 3 unmodified lines
44
55 #include <linux/atomic.h>
66 #include <linux/bitfield.h>
7+#include <linux/cleanup.h>
78 #include <linux/clk.h>
89 #include <linux/delay.h>
910 #include <linux/device.h>
@@ -25,6 +26,8 @@ · 15 unmodified lines
2526 #include <linux/workqueue.h>
2627 #include <linux/debugfs.h>
2728 #include <linux/ktime.h>
29+#include <linux/regmap.h>
30+#include <linux/mfd/syscon.h>
2831 #include <media/v4l2-ctrls.h>
2932 #include <media/v4l2-dev.h>
3033 #include <media/v4l2-device.h>
@@ -203,6 +206,25 @@ · 172 unmodified lines
203206 #define VE_MEM_RESTRICT_START 0x310
204207 #define VE_MEM_RESTRICT_END 0x314
205208
209+/* SCU's registers */
210+#define SCU_MISC_CTRL 0xC0
211+#define SCU_DPLL_SOURCE BIT(20)
212+
213+/* GFX's registers */
214+#define GFX_CTRL 0x60
215+#define GFX_CTRL_ENABLE BIT(0)
216+#define GFX_CTRL_FMT GENMASK(9, 7)
217+
218+#define GFX_H_DISPLAY 0x70
219+#define GFX_H_DISPLAY_DE GENMASK(28, 16)
220+#define GFX_H_DISPLAY_TOTAL GENMASK(12, 0)
221+
222+#define GFX_V_DISPLAY 0x78
223+#define GFX_V_DISPLAY_DE GENMASK(27, 16)
224+#define GFX_V_DISPLAY_TOTAL GENMASK(11, 0)
225+
226+#define GFX_DISPLAY_ADDR 0x80
227+
206228 /*
207229 * VIDEO_MODE_DETECT_DONE: a flag raised if signal lock
208230 * VIDEO_RES_CHANGE: a flag raised if res_change work on-going
@@ -262,6 +284,7 @@ struct aspeed_video_perf { · 53 unmodified lines
262284 /*
263285 * struct aspeed_video - driver data
264286 *
287+ * version: holds the version of aspeed SoC
265288 * res_work: holds the delayed_work for res-detection if unlock
266289 * buffers: holds the list of buffer queued from user
267290 * flags: holds the state of video
@@ -273,6 +296,7 @@ struct aspeed_video_perf { · 5 unmodified lines
273296 * yuv420: a flag raised if JPEG subsampling is 420
274297 * format: holds the video format
275298 * hq_mode: a flag raised if HQ is enabled. Only for VIDEO_FMT_ASPEED
299+ * input: holds the video input
276300 * frame_rate: holds the frame_rate
277301 * jpeg_quality: holds jpeq's quality (0~11)
278302 * jpeg_hq_quality: holds hq's quality (1~12) only if hq_mode enabled
@@ -298,6 +322,9 @@ struct aspeed_video { · 19 unmodified lines
298322 struct video_device vdev;
299323 struct mutex video_lock; /* v4l2 and videobuf2 lock */
300324
325+ struct regmap *scu;
326+ struct regmap *gfx;
327+ u32 version;
301328 u32 jpeg_mode;
302329 u32 comp_size_read;
303330
@@ -316,6 +343,7 @@ struct aspeed_video { · 12 unmodified lines
316343 bool yuv420;
317344 enum aspeed_video_format format;
318345 bool hq_mode;
346+ enum aspeed_video_input input;
319347 unsigned int frame_rate;
320348 unsigned int jpeg_quality;
321349 unsigned int jpeg_hq_quality;
@@ -331,21 +359,25 @@ struct aspeed_video { · 9 unmodified lines
331359 #define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev)
332360
333361 struct aspeed_video_config {
362+ u32 version;
334363 u32 jpeg_mode;
335364 u32 comp_size_read;
336365 };
337366
338367 static const struct aspeed_video_config ast2400_config = {
368+ .version = 4,
339369 .jpeg_mode = AST2400_VE_SEQ_CTRL_JPEG_MODE,
340370 .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK,
341371 };
342372
343373 static const struct aspeed_video_config ast2500_config = {
374+ .version = 5,
344375 .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE,
345376 .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK,
346377 };
347378
348379 static const struct aspeed_video_config ast2600_config = {
380+ .version = 6,
349381 .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE,
350382 .comp_size_read = AST2600_VE_COMP_SIZE_READ_BACK,
351383 };
@@ -485,6 +517,7 @@ static const struct v4l2_dv_timings_cap aspeed_video_timings_cap = { · 133 unmodified lines
485517
486518 static const char * const format_str[] = {"Standard JPEG",
487519 "Aspeed JPEG"};
520+static const char * const input_str[] = {"HOST VGA", "BMC GFX"};
488521
489522 static unsigned int debug;
490523
@@ -609,6 +642,14 @@ static int aspeed_video_start_frame(struct aspeed_video *video) · 118 unmodified lines
609642 aspeed_video_free_buf(video, &video->bcd);
610643 }
611644
645+ if (video->input == VIDEO_INPUT_GFX) {
646+ u32 val;
647+
648+ // update input buffer address as gfx's
649+ regmap_read(video->gfx, GFX_DISPLAY_ADDR, &val);
650+ aspeed_video_write(video, VE_TGS_0, val);
651+ }
652+
612653 spin_lock_irqsave(&video->lock, flags);
613654 buf = list_first_entry_or_null(&video->buffers,
614655 struct aspeed_video_buffer, link);
@@ -1026,9 +1067,23 @@ static void aspeed_video_get_timings(struct aspeed_video *v, · 411 unmodified lines
10261067 }
10271068 }
10281069
1070+static void aspeed_video_get_resolution_gfx(struct aspeed_video *video,
1071+ struct v4l2_bt_timings *det)
1072+{
1073+ u32 h_val, v_val;
1074+
1075+ regmap_read(video->gfx, GFX_H_DISPLAY, &h_val);
1076+ regmap_read(video->gfx, GFX_V_DISPLAY, &v_val);
1077+
1078+ det->width = FIELD_GET(GFX_H_DISPLAY_DE, h_val) + 1;
1079+ det->height = FIELD_GET(GFX_V_DISPLAY_DE, v_val) + 1;
1080+ video->v4l2_input_status = 0;
1081+}
1082+
10291083 #define res_check(v) test_and_clear_bit(VIDEO_MODE_DETECT_DONE, &(v)->flags)
10301084
1031−static void aspeed_video_get_resolution(struct aspeed_video *video)
1085+static void aspeed_video_get_resolution_vga(struct aspeed_video *video,
1086+ struct v4l2_bt_timings *det)
10321087 {
10331088 bool invalid_resolution = true;
10341089 int rc;
@@ -1036,7 +1091,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) · 1 unmodified line
10361091 u32 mds;
10371092 u32 src_lr_edge;
10381093 u32 src_tb_edge;
1039− struct v4l2_bt_timings *det = &video->detected_timings;
10401094
10411095 det->width = MIN_WIDTH;
10421096 det->height = MIN_HEIGHT;
@@ -1113,14 +1167,20 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) · 70 unmodified lines
11131167
11141168 aspeed_video_get_timings(video, det);
11151169
1116− /*
1117− * Enable mode-detect watchdog, resolution-change watchdog and
1118− * automatic compression after frame capture.
1119− */
1170+ /* Enable mode-detect watchdog, resolution-change watchdog */
11201171 aspeed_video_update(video, VE_INTERRUPT_CTRL, 0,
11211172 VE_INTERRUPT_MODE_DETECT_WD);
1122− aspeed_video_update(video, VE_SEQ_CTRL, 0,
1123− VE_SEQ_CTRL_AUTO_COMP | VE_SEQ_CTRL_EN_WATCHDOG);
1173+ aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_EN_WATCHDOG);
1174+}
1175+
1176+static void aspeed_video_get_resolution(struct aspeed_video *video)
1177+{
1178+ struct v4l2_bt_timings *det = &video->detected_timings;
1179+
1180+ if (video->input == VIDEO_INPUT_GFX)
1181+ aspeed_video_get_resolution_gfx(video, det);
1182+ else
1183+ aspeed_video_get_resolution_vga(video, det);
11241184
11251185 v4l2_dbg(1, debug, &video->v4l2_dev, "Got resolution: %dx%d\n",
11261186 det->width, det->height);
@@ -1156,7 +1216,7 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) · 29 unmodified lines
11561216 aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4);
11571217
11581218 /* Don't use direct mode below 1024 x 768 (irqs don't fire) */
1159− if (size < DIRECT_FETCH_THRESHOLD) {
1219+ if (video->input == VIDEO_INPUT_VGA && size < DIRECT_FETCH_THRESHOLD) {
11601220 v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Sync Mode\n");
11611221 aspeed_video_write(video, VE_TGS_0,
11621222 FIELD_PREP(VE_TGS_FIRST,
@@ -1171,10 +1231,20 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) · 8 unmodified lines
11711231 VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH,
11721232 VE_CTRL_INT_DE);
11731233 } else {
1234+ u32 ctrl, val, bpp;
1235+
11741236 v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Direct Mode\n");
1237+ ctrl = VE_CTRL_DIRECT_FETCH;
1238+ if (video->input == VIDEO_INPUT_GFX) {
1239+ regmap_read(video->gfx, GFX_CTRL, &val);
1240+ bpp = FIELD_GET(GFX_CTRL_FMT, val) ? 32 : 16;
1241+ if (bpp == 16)
1242+ ctrl |= VE_CTRL_INT_DE;
1243+ aspeed_video_write(video, VE_TGS_1, act->width * (bpp >> 3));
1244+ }
11751245 aspeed_video_update(video, VE_CTRL,
11761246 VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH,
1177− VE_CTRL_DIRECT_FETCH);
1247+ ctrl);
11781248 }
11791249
11801250 size *= 4;
@@ -1207,6 +1277,22 @@ err_mem: · 26 unmodified lines
12071277 aspeed_video_free_buf(video, &video->srcs[0]);
12081278 }
12091279
1280+/*
1281+ * Update relative parameters when timing changed.
1282+ *
1283+ * @video: the struct of aspeed_video
1284+ * @timings: the new timings
1285+ */
1286+static void aspeed_video_update_timings(struct aspeed_video *video, struct v4l2_bt_timings *timings)
1287+{
1288+ video->active_timings = *timings;
1289+ aspeed_video_set_resolution(video);
1290+
1291+ video->pix_fmt.width = timings->width;
1292+ video->pix_fmt.height = timings->height;
1293+ video->pix_fmt.sizeimage = video->max_compressed_size;
1294+}
1295+
12101296 static void aspeed_video_update_regs(struct aspeed_video *video)
12111297 {
12121298 u8 jpeg_hq_quality = clamp((int)video->jpeg_hq_quality - 1, 0,
@@ -1219,6 +1305,8 @@ static void aspeed_video_update_regs(struct aspeed_video *video) · 6 unmodified lines
12191305 u32 ctrl = 0;
12201306 u32 seq_ctrl = 0;
12211307
1308+ v4l2_dbg(1, debug, &video->v4l2_dev, "input(%s)\n",
1309+ input_str[video->input]);
12221310 v4l2_dbg(1, debug, &video->v4l2_dev, "framerate(%d)\n",
12231311 video->frame_rate);
12241312 v4l2_dbg(1, debug, &video->v4l2_dev, "jpeg format(%s) subsample(%s)\n",
@@ -1234,6 +1322,9 @@ static void aspeed_video_update_regs(struct aspeed_video *video) · 9 unmodified lines
12341322 else
12351323 aspeed_video_update(video, VE_BCD_CTRL, VE_BCD_CTRL_EN_BCD, 0);
12361324
1325+ if (video->input == VIDEO_INPUT_VGA)
1326+ ctrl |= VE_CTRL_AUTO_OR_CURSOR;
1327+
12371328 if (video->frame_rate)
12381329 ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate);
12391330
@@ -1252,7 +1343,9 @@ static void aspeed_video_update_regs(struct aspeed_video *video) · 12 unmodified lines
12521343 aspeed_video_update(video, VE_SEQ_CTRL,
12531344 video->jpeg_mode | VE_SEQ_CTRL_YUV420,
12541345 seq_ctrl);
1255− aspeed_video_update(video, VE_CTRL, VE_CTRL_FRC, ctrl);
1346+ aspeed_video_update(video, VE_CTRL,
1347+ VE_CTRL_FRC | VE_CTRL_AUTO_OR_CURSOR |
1348+ VE_CTRL_SOURCE, ctrl);
12561349 aspeed_video_update(video, VE_COMP_CTRL,
12571350 VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR |
12581351 VE_COMP_CTRL_EN_HQ | VE_COMP_CTRL_HQ_DCT_LUM |
@@ -1280,6 +1373,7 @@ static void aspeed_video_init_regs(struct aspeed_video *video) · 21 unmodified lines
12801373 aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma);
12811374
12821375 /* Set control registers */
1376+ aspeed_video_write(video, VE_SEQ_CTRL, VE_SEQ_CTRL_AUTO_COMP);
12831377 aspeed_video_write(video, VE_CTRL, ctrl);
12841378 aspeed_video_write(video, VE_COMP_CTRL, VE_COMP_CTRL_RSVD);
12851379
@@ -1311,12 +1405,7 @@ static void aspeed_video_start(struct aspeed_video *video) · 25 unmodified lines
13111405 aspeed_video_get_resolution(video);
13121406
13131407 /* Set timings since the device is being opened for the first time */
1314− video->active_timings = video->detected_timings;
1315− aspeed_video_set_resolution(video);
1316−
1317− video->pix_fmt.width = video->active_timings.width;
1318− video->pix_fmt.height = video->active_timings.height;
1319− video->pix_fmt.sizeimage = video->max_compressed_size;
1408+ aspeed_video_update_timings(video, &video->detected_timings);
13201409 }
13211410
13221411 static void aspeed_video_stop(struct aspeed_video *video)
@@ -1401,10 +1490,10 @@ static int aspeed_video_enum_input(struct file *file, void *fh, · 78 unmodified lines
14011490 {
14021491 struct aspeed_video *video = video_drvdata(file);
14031492
1404− if (inp->index)
1493+ if (inp->index >= VIDEO_INPUT_MAX)
14051494 return -EINVAL;
14061495
1407− strscpy(inp->name, "Host VGA capture", sizeof(inp->name));
1496+ sprintf(inp->name, "%s capture", input_str[inp->index]);
14081497 inp->type = V4L2_INPUT_TYPE_CAMERA;
14091498 inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
14101499 inp->status = video->v4l2_input_status;
@@ -1414,16 +1503,57 @@ static int aspeed_video_enum_input(struct file *file, void *fh, · 3 unmodified lines
14141503
14151504 static int aspeed_video_get_input(struct file *file, void *fh, unsigned int *i)
14161505 {
1417− *i = 0;
1506+ struct aspeed_video *video = video_drvdata(file);
1507+
1508+ *i = video->input;
14181509
14191510 return 0;
14201511 }
14211512
14221513 static int aspeed_video_set_input(struct file *file, void *fh, unsigned int i)
14231514 {
1424− if (i)
1515+ struct aspeed_video *video = video_drvdata(file);
1516+
1517+ if (i >= VIDEO_INPUT_MAX)
14251518 return -EINVAL;
14261519
1520+ if (i == video->input)
1521+ return 0;
1522+
1523+ if (vb2_is_busy(&video->queue))
1524+ return -EBUSY;
1525+
1526+ if (IS_ERR(video->scu)) {
1527+ v4l2_dbg(1, debug, &video->v4l2_dev,
1528+ "%s: scu isn't ready for input-control\n", __func__);
1529+ return -EINVAL;
1530+ }
1531+
1532+ if (IS_ERR(video->gfx) && i == VIDEO_INPUT_GFX) {
1533+ v4l2_dbg(1, debug, &video->v4l2_dev,
1534+ "%s: gfx isn't ready for GFX input\n", __func__);
1535+ return -EINVAL;
1536+ }
1537+
1538+ video->input = i;
1539+
1540+ if (video->version == 6) {
1541+ /* modify dpll source per current input */
1542+ if (video->input == VIDEO_INPUT_VGA)
1543+ regmap_update_bits(video->scu, SCU_MISC_CTRL,
1544+ SCU_DPLL_SOURCE, 0);
1545+ else
1546+ regmap_update_bits(video->scu, SCU_MISC_CTRL,
1547+ SCU_DPLL_SOURCE, SCU_DPLL_SOURCE);
1548+ }
1549+
1550+ aspeed_video_update_regs(video);
1551+
1552+ /* update signal status */
1553+ aspeed_video_get_resolution(video);
1554+ if (!video->v4l2_input_status)
1555+ aspeed_video_update_timings(video, &video->detected_timings);
1556+
14271557 return 0;
14281558 }
14291559
@@ -1527,13 +1657,7 @@ static int aspeed_video_set_dv_timings(struct file *file, void *fh, · 97 unmodified lines
15271657 if (vb2_is_busy(&video->queue))
15281658 return -EBUSY;
15291659
1530− video->active_timings = timings->bt;
1531−
1532− aspeed_video_set_resolution(video);
1533−
1534− video->pix_fmt.width = timings->bt.width;
1535− video->pix_fmt.height = timings->bt.height;
1536− video->pix_fmt.sizeimage = video->max_compressed_size;
1660+ aspeed_video_update_timings(video, &timings->bt);
15371661
15381662 timings->type = V4L2_DV_BT_656_1120;
15391663
@@ -1909,6 +2033,7 @@ static int aspeed_video_debugfs_show(struct seq_file *s, void *data) · 369 unmodified lines
19092033 val08 = aspeed_video_read(v, VE_CTRL);
19102034 if (FIELD_GET(VE_CTRL_DIRECT_FETCH, val08)) {
19112035 seq_printf(s, " %-20s:\tDirect fetch\n", "Mode");
2036+ seq_printf(s, " %-20s:\t%s\n", "Input", input_str[v->input]);
19122037 seq_printf(s, " %-20s:\t%s\n", "VGA bpp mode",
19132038 FIELD_GET(VE_CTRL_INT_DE, val08) ? "16" : "32");
19142039 } else {
@@ -2068,12 +2193,29 @@ static int aspeed_video_setup_video(struct aspeed_video *video) · 153 unmodified lines
20682193 return 0;
20692194 }
20702195
2196+/*
2197+ * Get regmap without checking res, such as clk/reset, that could lead to
2198+ * conflict.
2199+ */
2200+static struct regmap *aspeed_regmap_lookup(struct device_node *np, const char *property)
2201+{
2202+ struct device_node *syscon_np __free(device_node) = of_parse_phandle(np, property, 0);
2203+
2204+ if (!syscon_np)
2205+ return ERR_PTR(-ENODEV);
2206+
2207+ return device_node_to_regmap(syscon_np);
2208+}
2209+
20712210 static int aspeed_video_init(struct aspeed_video *video)
20722211 {
20732212 int irq;
20742213 int rc;
20752214 struct device *dev = video->dev;
20762215
2216+ video->scu = aspeed_regmap_lookup(dev->of_node, "aspeed,scu");
2217+ video->gfx = aspeed_regmap_lookup(dev->of_node, "aspeed,gfx");
2218+
20772219 irq = irq_of_parse_and_map(dev->of_node, 0);
20782220 if (!irq) {
20792221 dev_err(dev, "Unable to find IRQ\n");
@@ -2165,6 +2307,7 @@ static int aspeed_video_probe(struct platform_device *pdev) · 85 unmodified lines
21652307 if (!config)
21662308 return -ENODEV;
21672309
2310+ video->version = config->version;
21682311 video->jpeg_mode = config->jpeg_mode;
21692312 video->comp_size_read = config->comp_size_read;
21702313
include/uapi/linux/aspeed-video.h+7−0
@@ -8,6 +8,13 @@ · 7 unmodified lines
88
99 #include <linux/v4l2-controls.h>
1010
11+/* aspeed video's input types */
12+enum aspeed_video_input {
13+ VIDEO_INPUT_VGA = 0,
14+ VIDEO_INPUT_GFX,
15+ VIDEO_INPUT_MAX
16+};
17+
1118 #define V4L2_CID_ASPEED_HQ_MODE (V4L2_CID_USER_ASPEED_BASE + 1)
1219 #define V4L2_CID_ASPEED_HQ_JPEG_QUALITY (V4L2_CID_USER_ASPEED_BASE + 2)
1320

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t