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) { ... }
Unified · Split
| @@ -4,6 +4,7 @@ · 3 unmodified lines | |||
| 4 | 4 | ||
| 5 | #include <linux/atomic.h> | 5 | #include <linux/atomic.h> |
| 6 | #include <linux/bitfield.h> | 6 | #include <linux/bitfield.h> |
| 7 | #include <linux/cleanup.h> | ||
| 7 | #include <linux/clk.h> | 8 | #include <linux/clk.h> |
| 8 | #include <linux/delay.h> | 9 | #include <linux/delay.h> |
| 9 | #include <linux/device.h> | 10 | #include <linux/device.h> |
| @@ -25,6 +26,8 @@ · 15 unmodified lines | |||
| 25 | #include <linux/workqueue.h> | 26 | #include <linux/workqueue.h> |
| 26 | #include <linux/debugfs.h> | 27 | #include <linux/debugfs.h> |
| 27 | #include <linux/ktime.h> | 28 | #include <linux/ktime.h> |
| 29 | #include <linux/regmap.h> | ||
| 30 | #include <linux/mfd/syscon.h> | ||
| 28 | #include <media/v4l2-ctrls.h> | 31 | #include <media/v4l2-ctrls.h> |
| 29 | #include <media/v4l2-dev.h> | 32 | #include <media/v4l2-dev.h> |
| 30 | #include <media/v4l2-device.h> | 33 | #include <media/v4l2-device.h> |
| @@ -203,6 +206,25 @@ · 172 unmodified lines | |||
| 203 | #define VE_MEM_RESTRICT_START 0x310 | 206 | #define VE_MEM_RESTRICT_START 0x310 |
| 204 | #define VE_MEM_RESTRICT_END 0x314 | 207 | #define VE_MEM_RESTRICT_END 0x314 |
| 205 | 208 | ||
| 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 | |||
| 206 | /* | 228 | /* |
| 207 | * VIDEO_MODE_DETECT_DONE: a flag raised if signal lock | 229 | * VIDEO_MODE_DETECT_DONE: a flag raised if signal lock |
| 208 | * VIDEO_RES_CHANGE: a flag raised if res_change work on-going | 230 | * VIDEO_RES_CHANGE: a flag raised if res_change work on-going |
| @@ -262,6 +284,7 @@ struct aspeed_video_perf { · 53 unmodified lines | |||
| 262 | /* | 284 | /* |
| 263 | * struct aspeed_video - driver data | 285 | * struct aspeed_video - driver data |
| 264 | * | 286 | * |
| 287 | * version: holds the version of aspeed SoC | ||
| 265 | * res_work: holds the delayed_work for res-detection if unlock | 288 | * res_work: holds the delayed_work for res-detection if unlock |
| 266 | * buffers: holds the list of buffer queued from user | 289 | * buffers: holds the list of buffer queued from user |
| 267 | * flags: holds the state of video | 290 | * flags: holds the state of video |
| @@ -273,6 +296,7 @@ struct aspeed_video_perf { · 5 unmodified lines | |||
| 273 | * yuv420: a flag raised if JPEG subsampling is 420 | 296 | * yuv420: a flag raised if JPEG subsampling is 420 |
| 274 | * format: holds the video format | 297 | * format: holds the video format |
| 275 | * hq_mode: a flag raised if HQ is enabled. Only for VIDEO_FMT_ASPEED | 298 | * hq_mode: a flag raised if HQ is enabled. Only for VIDEO_FMT_ASPEED |
| 299 | * input: holds the video input | ||
| 276 | * frame_rate: holds the frame_rate | 300 | * frame_rate: holds the frame_rate |
| 277 | * jpeg_quality: holds jpeq's quality (0~11) | 301 | * jpeg_quality: holds jpeq's quality (0~11) |
| 278 | * jpeg_hq_quality: holds hq's quality (1~12) only if hq_mode enabled | 302 | * jpeg_hq_quality: holds hq's quality (1~12) only if hq_mode enabled |
| @@ -298,6 +322,9 @@ struct aspeed_video { · 19 unmodified lines | |||
| 298 | struct video_device vdev; | 322 | struct video_device vdev; |
| 299 | struct mutex video_lock; /* v4l2 and videobuf2 lock */ | 323 | struct mutex video_lock; /* v4l2 and videobuf2 lock */ |
| 300 | 324 | ||
| 325 | struct regmap *scu; | ||
| 326 | struct regmap *gfx; | ||
| 327 | u32 version; | ||
| 301 | u32 jpeg_mode; | 328 | u32 jpeg_mode; |
| 302 | u32 comp_size_read; | 329 | u32 comp_size_read; |
| 303 | 330 | ||
| @@ -316,6 +343,7 @@ struct aspeed_video { · 12 unmodified lines | |||
| 316 | bool yuv420; | 343 | bool yuv420; |
| 317 | enum aspeed_video_format format; | 344 | enum aspeed_video_format format; |
| 318 | bool hq_mode; | 345 | bool hq_mode; |
| 346 | enum aspeed_video_input input; | ||
| 319 | unsigned int frame_rate; | 347 | unsigned int frame_rate; |
| 320 | unsigned int jpeg_quality; | 348 | unsigned int jpeg_quality; |
| 321 | unsigned int jpeg_hq_quality; | 349 | unsigned int jpeg_hq_quality; |
| @@ -331,21 +359,25 @@ struct aspeed_video { · 9 unmodified lines | |||
| 331 | #define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev) | 359 | #define to_aspeed_video(x) container_of((x), struct aspeed_video, v4l2_dev) |
| 332 | 360 | ||
| 333 | struct aspeed_video_config { | 361 | struct aspeed_video_config { |
| 362 | u32 version; | ||
| 334 | u32 jpeg_mode; | 363 | u32 jpeg_mode; |
| 335 | u32 comp_size_read; | 364 | u32 comp_size_read; |
| 336 | }; | 365 | }; |
| 337 | 366 | ||
| 338 | static const struct aspeed_video_config ast2400_config = { | 367 | static const struct aspeed_video_config ast2400_config = { |
| 368 | .version = 4, | ||
| 339 | .jpeg_mode = AST2400_VE_SEQ_CTRL_JPEG_MODE, | 369 | .jpeg_mode = AST2400_VE_SEQ_CTRL_JPEG_MODE, |
| 340 | .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, | 370 | .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, |
| 341 | }; | 371 | }; |
| 342 | 372 | ||
| 343 | static const struct aspeed_video_config ast2500_config = { | 373 | static const struct aspeed_video_config ast2500_config = { |
| 374 | .version = 5, | ||
| 344 | .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, | 375 | .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, |
| 345 | .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, | 376 | .comp_size_read = AST2400_VE_COMP_SIZE_READ_BACK, |
| 346 | }; | 377 | }; |
| 347 | 378 | ||
| 348 | static const struct aspeed_video_config ast2600_config = { | 379 | static const struct aspeed_video_config ast2600_config = { |
| 380 | .version = 6, | ||
| 349 | .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, | 381 | .jpeg_mode = AST2500_VE_SEQ_CTRL_JPEG_MODE, |
| 350 | .comp_size_read = AST2600_VE_COMP_SIZE_READ_BACK, | 382 | .comp_size_read = AST2600_VE_COMP_SIZE_READ_BACK, |
| 351 | }; | 383 | }; |
| @@ -485,6 +517,7 @@ static const struct v4l2_dv_timings_cap aspeed_video_timings_cap = { · 133 unmodified lines | |||
| 485 | 517 | ||
| 486 | static const char * const format_str[] = {"Standard JPEG", | 518 | static const char * const format_str[] = {"Standard JPEG", |
| 487 | "Aspeed JPEG"}; | 519 | "Aspeed JPEG"}; |
| 520 | static const char * const input_str[] = {"HOST VGA", "BMC GFX"}; | ||
| 488 | 521 | ||
| 489 | static unsigned int debug; | 522 | static unsigned int debug; |
| 490 | 523 | ||
| @@ -609,6 +642,14 @@ static int aspeed_video_start_frame(struct aspeed_video *video) · 118 unmodified lines | |||
| 609 | aspeed_video_free_buf(video, &video->bcd); | 642 | aspeed_video_free_buf(video, &video->bcd); |
| 610 | } | 643 | } |
| 611 | 644 | ||
| 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 | |||
| 612 | spin_lock_irqsave(&video->lock, flags); | 653 | spin_lock_irqsave(&video->lock, flags); |
| 613 | buf = list_first_entry_or_null(&video->buffers, | 654 | buf = list_first_entry_or_null(&video->buffers, |
| 614 | struct aspeed_video_buffer, link); | 655 | struct aspeed_video_buffer, link); |
| @@ -1026,9 +1067,23 @@ static void aspeed_video_get_timings(struct aspeed_video *v, · 411 unmodified lines | |||
| 1026 | } | 1067 | } |
| 1027 | } | 1068 | } |
| 1028 | 1069 | ||
| 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 | |||
| 1029 | #define res_check(v) test_and_clear_bit(VIDEO_MODE_DETECT_DONE, &(v)->flags) | 1083 | #define res_check(v) test_and_clear_bit(VIDEO_MODE_DETECT_DONE, &(v)->flags) |
| 1030 | 1084 | ||
| 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) | ||
| 1032 | { | 1087 | { |
| 1033 | bool invalid_resolution = true; | 1088 | bool invalid_resolution = true; |
| 1034 | int rc; | 1089 | int rc; |
| @@ -1036,7 +1091,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) · 1 unmodified line | |||
| 1036 | u32 mds; | 1091 | u32 mds; |
| 1037 | u32 src_lr_edge; | 1092 | u32 src_lr_edge; |
| 1038 | u32 src_tb_edge; | 1093 | u32 src_tb_edge; |
| 1039 | struct v4l2_bt_timings *det = &video->detected_timings; | ||
| 1040 | 1094 | ||
| 1041 | det->width = MIN_WIDTH; | 1095 | det->width = MIN_WIDTH; |
| 1042 | det->height = MIN_HEIGHT; | 1096 | det->height = MIN_HEIGHT; |
| @@ -1113,14 +1167,20 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) · 70 unmodified lines | |||
| 1113 | 1167 | ||
| 1114 | aspeed_video_get_timings(video, det); | 1168 | aspeed_video_get_timings(video, det); |
| 1115 | 1169 | ||
| 1116 | /* | 1170 | /* Enable mode-detect watchdog, resolution-change watchdog */ |
| 1117 | * Enable mode-detect watchdog, resolution-change watchdog and | ||
| 1118 | * automatic compression after frame capture. | ||
| 1119 | */ | ||
| 1120 | aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, | 1171 | aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, |
| 1121 | VE_INTERRUPT_MODE_DETECT_WD); | 1172 | VE_INTERRUPT_MODE_DETECT_WD); |
| 1122 | aspeed_video_update(video, VE_SEQ_CTRL, 0, | 1173 | aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_EN_WATCHDOG); |
| 1123 | VE_SEQ_CTRL_AUTO_COMP | 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); | ||
| 1124 | 1184 | ||
| 1125 | v4l2_dbg(1, debug, &video->v4l2_dev, "Got resolution: %dx%d\n", | 1185 | v4l2_dbg(1, debug, &video->v4l2_dev, "Got resolution: %dx%d\n", |
| 1126 | det->width, det->height); | 1186 | det->width, det->height); |
| @@ -1156,7 +1216,7 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) · 29 unmodified lines | |||
| 1156 | aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4); | 1216 | aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4); |
| 1157 | 1217 | ||
| 1158 | /* Don't use direct mode below 1024 x 768 (irqs don't fire) */ | 1218 | /* 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) { |
| 1160 | v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Sync Mode\n"); | 1220 | v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Sync Mode\n"); |
| 1161 | aspeed_video_write(video, VE_TGS_0, | 1221 | aspeed_video_write(video, VE_TGS_0, |
| 1162 | FIELD_PREP(VE_TGS_FIRST, | 1222 | FIELD_PREP(VE_TGS_FIRST, |
| @@ -1171,10 +1231,20 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) · 8 unmodified lines | |||
| 1171 | VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, | 1231 | VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, |
| 1172 | VE_CTRL_INT_DE); | 1232 | VE_CTRL_INT_DE); |
| 1173 | } else { | 1233 | } else { |
| 1234 | u32 ctrl, val, bpp; | ||
| 1235 | |||
| 1174 | v4l2_dbg(1, debug, &video->v4l2_dev, "Capture: Direct Mode\n"); | 1236 | 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 | } | ||
| 1175 | aspeed_video_update(video, VE_CTRL, | 1245 | aspeed_video_update(video, VE_CTRL, |
| 1176 | VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, | 1246 | VE_CTRL_INT_DE | VE_CTRL_DIRECT_FETCH, |
| 1177 | VE_CTRL_DIRECT_FETCH); | 1247 | ctrl); |
| 1178 | } | 1248 | } |
| 1179 | 1249 | ||
| 1180 | size *= 4; | 1250 | size *= 4; |
| @@ -1207,6 +1277,22 @@ err_mem: · 26 unmodified lines | |||
| 1207 | aspeed_video_free_buf(video, &video->srcs[0]); | 1277 | aspeed_video_free_buf(video, &video->srcs[0]); |
| 1208 | } | 1278 | } |
| 1209 | 1279 | ||
| 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 | |||
| 1210 | static void aspeed_video_update_regs(struct aspeed_video *video) | 1296 | static void aspeed_video_update_regs(struct aspeed_video *video) |
| 1211 | { | 1297 | { |
| 1212 | u8 jpeg_hq_quality = clamp((int)video->jpeg_hq_quality - 1, 0, | 1298 | 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 | |||
| 1219 | u32 ctrl = 0; | 1305 | u32 ctrl = 0; |
| 1220 | u32 seq_ctrl = 0; | 1306 | u32 seq_ctrl = 0; |
| 1221 | 1307 | ||
| 1308 | v4l2_dbg(1, debug, &video->v4l2_dev, "input(%s)\n", | ||
| 1309 | input_str[video->input]); | ||
| 1222 | v4l2_dbg(1, debug, &video->v4l2_dev, "framerate(%d)\n", | 1310 | v4l2_dbg(1, debug, &video->v4l2_dev, "framerate(%d)\n", |
| 1223 | video->frame_rate); | 1311 | video->frame_rate); |
| 1224 | v4l2_dbg(1, debug, &video->v4l2_dev, "jpeg format(%s) subsample(%s)\n", | 1312 | 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 | |||
| 1234 | else | 1322 | else |
| 1235 | aspeed_video_update(video, VE_BCD_CTRL, VE_BCD_CTRL_EN_BCD, 0); | 1323 | aspeed_video_update(video, VE_BCD_CTRL, VE_BCD_CTRL_EN_BCD, 0); |
| 1236 | 1324 | ||
| 1325 | if (video->input == VIDEO_INPUT_VGA) | ||
| 1326 | ctrl |= VE_CTRL_AUTO_OR_CURSOR; | ||
| 1327 | |||
| 1237 | if (video->frame_rate) | 1328 | if (video->frame_rate) |
| 1238 | ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate); | 1329 | ctrl |= FIELD_PREP(VE_CTRL_FRC, video->frame_rate); |
| 1239 | 1330 | ||
| @@ -1252,7 +1343,9 @@ static void aspeed_video_update_regs(struct aspeed_video *video) · 12 unmodified lines | |||
| 1252 | aspeed_video_update(video, VE_SEQ_CTRL, | 1343 | aspeed_video_update(video, VE_SEQ_CTRL, |
| 1253 | video->jpeg_mode | VE_SEQ_CTRL_YUV420, | 1344 | video->jpeg_mode | VE_SEQ_CTRL_YUV420, |
| 1254 | seq_ctrl); | 1345 | 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); | ||
| 1256 | aspeed_video_update(video, VE_COMP_CTRL, | 1349 | aspeed_video_update(video, VE_COMP_CTRL, |
| 1257 | VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR | | 1350 | VE_COMP_CTRL_DCT_LUM | VE_COMP_CTRL_DCT_CHR | |
| 1258 | VE_COMP_CTRL_EN_HQ | VE_COMP_CTRL_HQ_DCT_LUM | | 1351 | 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 | |||
| 1280 | aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma); | 1373 | aspeed_video_write(video, VE_JPEG_ADDR, video->jpeg.dma); |
| 1281 | 1374 | ||
| 1282 | /* Set control registers */ | 1375 | /* Set control registers */ |
| 1376 | aspeed_video_write(video, VE_SEQ_CTRL, VE_SEQ_CTRL_AUTO_COMP); | ||
| 1283 | aspeed_video_write(video, VE_CTRL, ctrl); | 1377 | aspeed_video_write(video, VE_CTRL, ctrl); |
| 1284 | aspeed_video_write(video, VE_COMP_CTRL, VE_COMP_CTRL_RSVD); | 1378 | aspeed_video_write(video, VE_COMP_CTRL, VE_COMP_CTRL_RSVD); |
| 1285 | 1379 | ||
| @@ -1311,12 +1405,7 @@ static void aspeed_video_start(struct aspeed_video *video) · 25 unmodified lines | |||
| 1311 | aspeed_video_get_resolution(video); | 1405 | aspeed_video_get_resolution(video); |
| 1312 | 1406 | ||
| 1313 | /* Set timings since the device is being opened for the first time */ | 1407 | /* Set timings since the device is being opened for the first time */ |
| 1314 | video->active_timings = video->detected_timings; | 1408 | aspeed_video_update_timings(video, &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; | ||
| 1320 | } | 1409 | } |
| 1321 | 1410 | ||
| 1322 | static void aspeed_video_stop(struct aspeed_video *video) | 1411 | 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 | |||
| 1401 | { | 1490 | { |
| 1402 | struct aspeed_video *video = video_drvdata(file); | 1491 | struct aspeed_video *video = video_drvdata(file); |
| 1403 | 1492 | ||
| 1404 | if (inp->index) | 1493 | if (inp->index >= VIDEO_INPUT_MAX) |
| 1405 | return -EINVAL; | 1494 | return -EINVAL; |
| 1406 | 1495 | ||
| 1407 | strscpy(inp->name, "Host VGA capture", sizeof(inp->name)); | 1496 | sprintf(inp->name, "%s capture", input_str[inp->index]); |
| 1408 | inp->type = V4L2_INPUT_TYPE_CAMERA; | 1497 | inp->type = V4L2_INPUT_TYPE_CAMERA; |
| 1409 | inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; | 1498 | inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; |
| 1410 | inp->status = video->v4l2_input_status; | 1499 | inp->status = video->v4l2_input_status; |
| @@ -1414,16 +1503,57 @@ static int aspeed_video_enum_input(struct file *file, void *fh, · 3 unmodified lines | |||
| 1414 | 1503 | ||
| 1415 | static int aspeed_video_get_input(struct file *file, void *fh, unsigned int *i) | 1504 | static int aspeed_video_get_input(struct file *file, void *fh, unsigned int *i) |
| 1416 | { | 1505 | { |
| 1417 | *i = 0; | 1506 | struct aspeed_video *video = video_drvdata(file); |
| 1507 | |||
| 1508 | *i = video->input; | ||
| 1418 | 1509 | ||
| 1419 | return 0; | 1510 | return 0; |
| 1420 | } | 1511 | } |
| 1421 | 1512 | ||
| 1422 | static int aspeed_video_set_input(struct file *file, void *fh, unsigned int i) | 1513 | static int aspeed_video_set_input(struct file *file, void *fh, unsigned int i) |
| 1423 | { | 1514 | { |
| 1424 | if (i) | 1515 | struct aspeed_video *video = video_drvdata(file); |
| 1516 | |||
| 1517 | if (i >= VIDEO_INPUT_MAX) | ||
| 1425 | return -EINVAL; | 1518 | return -EINVAL; |
| 1426 | 1519 | ||
| 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 | |||
| 1427 | return 0; | 1557 | return 0; |
| 1428 | } | 1558 | } |
| 1429 | 1559 | ||
| @@ -1527,13 +1657,7 @@ static int aspeed_video_set_dv_timings(struct file *file, void *fh, · 97 unmodified lines | |||
| 1527 | if (vb2_is_busy(&video->queue)) | 1657 | if (vb2_is_busy(&video->queue)) |
| 1528 | return -EBUSY; | 1658 | return -EBUSY; |
| 1529 | 1659 | ||
| 1530 | video->active_timings = timings->bt; | 1660 | aspeed_video_update_timings(video, &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; | ||
| 1537 | 1661 | ||
| 1538 | timings->type = V4L2_DV_BT_656_1120; | 1662 | timings->type = V4L2_DV_BT_656_1120; |
| 1539 | 1663 | ||
| @@ -1909,6 +2033,7 @@ static int aspeed_video_debugfs_show(struct seq_file *s, void *data) · 369 unmodified lines | |||
| 1909 | val08 = aspeed_video_read(v, VE_CTRL); | 2033 | val08 = aspeed_video_read(v, VE_CTRL); |
| 1910 | if (FIELD_GET(VE_CTRL_DIRECT_FETCH, val08)) { | 2034 | if (FIELD_GET(VE_CTRL_DIRECT_FETCH, val08)) { |
| 1911 | seq_printf(s, " %-20s:\tDirect fetch\n", "Mode"); | 2035 | seq_printf(s, " %-20s:\tDirect fetch\n", "Mode"); |
| 2036 | seq_printf(s, " %-20s:\t%s\n", "Input", input_str[v->input]); | ||
| 1912 | seq_printf(s, " %-20s:\t%s\n", "VGA bpp mode", | 2037 | seq_printf(s, " %-20s:\t%s\n", "VGA bpp mode", |
| 1913 | FIELD_GET(VE_CTRL_INT_DE, val08) ? "16" : "32"); | 2038 | FIELD_GET(VE_CTRL_INT_DE, val08) ? "16" : "32"); |
| 1914 | } else { | 2039 | } else { |
| @@ -2068,12 +2193,29 @@ static int aspeed_video_setup_video(struct aspeed_video *video) · 153 unmodified lines | |||
| 2068 | return 0; | 2193 | return 0; |
| 2069 | } | 2194 | } |
| 2070 | 2195 | ||
| 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 | |||
| 2071 | static int aspeed_video_init(struct aspeed_video *video) | 2210 | static int aspeed_video_init(struct aspeed_video *video) |
| 2072 | { | 2211 | { |
| 2073 | int irq; | 2212 | int irq; |
| 2074 | int rc; | 2213 | int rc; |
| 2075 | struct device *dev = video->dev; | 2214 | struct device *dev = video->dev; |
| 2076 | 2215 | ||
| 2216 | video->scu = aspeed_regmap_lookup(dev->of_node, "aspeed,scu"); | ||
| 2217 | video->gfx = aspeed_regmap_lookup(dev->of_node, "aspeed,gfx"); | ||
| 2218 | |||
| 2077 | irq = irq_of_parse_and_map(dev->of_node, 0); | 2219 | irq = irq_of_parse_and_map(dev->of_node, 0); |
| 2078 | if (!irq) { | 2220 | if (!irq) { |
| 2079 | dev_err(dev, "Unable to find IRQ\n"); | 2221 | dev_err(dev, "Unable to find IRQ\n"); |
| @@ -2165,6 +2307,7 @@ static int aspeed_video_probe(struct platform_device *pdev) · 85 unmodified lines | |||
| 2165 | if (!config) | 2307 | if (!config) |
| 2166 | return -ENODEV; | 2308 | return -ENODEV; |
| 2167 | 2309 | ||
| 2310 | video->version = config->version; | ||
| 2168 | video->jpeg_mode = config->jpeg_mode; | 2311 | video->jpeg_mode = config->jpeg_mode; |
| 2169 | video->comp_size_read = config->comp_size_read; | 2312 | video->comp_size_read = config->comp_size_read; |
| 2170 | 2313 | ||
| @@ -8,6 +8,13 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #include <linux/v4l2-controls.h> | 9 | #include <linux/v4l2-controls.h> |
| 10 | 10 | ||
| 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 | |||
| 11 | #define V4L2_CID_ASPEED_HQ_MODE (V4L2_CID_USER_ASPEED_BASE + 1) | 18 | #define V4L2_CID_ASPEED_HQ_MODE (V4L2_CID_USER_ASPEED_BASE + 1) |
| 12 | #define V4L2_CID_ASPEED_HQ_JPEG_QUALITY (V4L2_CID_USER_ASPEED_BASE + 2) | 19 | #define V4L2_CID_ASPEED_HQ_JPEG_QUALITY (V4L2_CID_USER_ASPEED_BASE + 2) |
| 13 | 20 | ||