diff --git a/drivers/media/platform/phytium/Kconfig b/drivers/media/platform/phytium/Kconfig index 498314fbfc947..3ee2e288ffdaa 100644 --- a/drivers/media/platform/phytium/Kconfig +++ b/drivers/media/platform/phytium/Kconfig @@ -6,6 +6,7 @@ config VIDEO_PHYTIUM_JPEG tristate "Phytium JPEG Encoder Engine driver" depends on V4L_PLATFORM_DRIVERS depends on VIDEO_DEV + depends on ARCH_PHYTIUM select VIDEOBUF2_DMA_CONTIG help Support for the Phytium JPEG Encoder Engine embedded diff --git a/drivers/media/platform/phytium/phytium_jpeg_core.c b/drivers/media/platform/phytium/phytium_jpeg_core.c index 540359974a419..c6ca52a3ca398 100644 --- a/drivers/media/platform/phytium/phytium_jpeg_core.c +++ b/drivers/media/platform/phytium/phytium_jpeg_core.c @@ -186,9 +186,6 @@ static void phytium_jpeg_off(struct phytium_jpeg_dev *jpeg_dev) } clear_bit(VIDEO_CLOCKS_ON, &jpeg_dev->status); - /* wait 50 ms */ - mdelay(50); - /* C08 bit7 1:busy */ } static inline void phytium_jpeg_enable_source_detecting(struct phytium_jpeg_dev *jpeg_dev) @@ -210,22 +207,47 @@ static void phytium_jpeg_get_resolution(struct phytium_jpeg_dev *jpeg_dev) u32 width; u32 height; struct v4l2_bt_timings *detected_timings = &jpeg_dev->detected_timings; + u32 input_signal; /* Before get a new resolution, maybe need to wait 10 us */ detected_timings->width = MIN_WIDTH; detected_timings->height = MIN_HEIGHT; jpeg_dev->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; - phytium_jpeg_enable_source_detecting(jpeg_dev); source_info = phytium_jpeg_read(jpeg_dev, SRC_VGA_INFO_REG); width = (source_info & SRC_HOR_PIXELS) >> SRC_WIDTH_SHIFT; height = (source_info & SRC_VER_PIXELS) >> SRC_HEIGHT_SHIFT; + input_signal = phytium_jpeg_read(jpeg_dev, BUF_LIST_INDEX_ADDR(VB_BUF_LAST)); + dev_dbg(jpeg_dev->dev, "get resolution: %uX%u, power 0x%x, once_power %u.\n", + width, height, input_signal, jpeg_dev->once_poweroff); + /* The resolution is 640*480 and V4L2_IN_ST_NO_SIGNAL in the case that host is poweroff. */ + if (input_signal == HOST_POWER_OFF) { + dev_dbg(jpeg_dev->dev, "Host is poweroff.\n"); + jpeg_dev->once_poweroff = true; + return; + } + + /* Host machine has never been poweroff since JPEG driver starts running */ + if (jpeg_dev->once_poweroff == false) { + input_signal = HAVE_SIGNAL; + phytium_jpeg_write(jpeg_dev, BUF_LIST_INDEX_ADDR(VB_BUF_LAST), HAVE_SIGNAL); + } else if (input_signal == HOST_POWER_ON) { + dev_dbg(jpeg_dev->dev, "No signal on KVM.\n"); + return; + } + + if ((input_signal == HAVE_SIGNAL && width * height != 0) || + test_bit(VIDEO_RES_CHANGE, &jpeg_dev->status)) { + jpeg_dev->v4l2_input_status = 0; + dev_dbg(jpeg_dev->dev, "output signal, status 0x%lx.\n", jpeg_dev->status); + } + + if (width * height != 0) { detected_timings->width = width; detected_timings->height = height; - jpeg_dev->v4l2_input_status = 0; cur_non_zero = true; } else { /* filter some repeated log-print lines */ @@ -492,11 +514,8 @@ static int phytium_jpeg_query_dv_timings(struct file *file, void *priv, struct v4l2_dv_timings *timings) { int ret; - u32 source_info; - u32 width; - u32 height; struct phytium_jpeg_dev *jpeg_dev = video_drvdata(file); - + u32 input_signal; /* * This blocks only if the driver is currently in the process of * detecting a new resolution; in the event of no signal or timeout @@ -516,13 +535,9 @@ static int phytium_jpeg_query_dv_timings(struct file *file, void *priv, timings->type = V4L2_DV_BT_656_1120; timings->bt = jpeg_dev->detected_timings; - /* Get resolution from SRC_VGA_INFO_REG */ - source_info = phytium_jpeg_read(jpeg_dev, SRC_VGA_INFO_REG); - width = (source_info & SRC_HOR_PIXELS) >> SRC_WIDTH_SHIFT; - height = (source_info & SRC_VER_PIXELS) >> SRC_HEIGHT_SHIFT; - - /* Check if that the current resolution is zero. */ - if (width == 0 || height == 0) + input_signal = phytium_jpeg_read(jpeg_dev, BUF_LIST_INDEX_ADDR(VB_BUF_LAST)); + /* Check if that the power status of the host machine resolution */ + if (input_signal != HAVE_SIGNAL) jpeg_dev->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; return jpeg_dev->v4l2_input_status ? -ENOLINK : 0; @@ -820,8 +835,14 @@ static void phytium_jpeg_resolution_work(struct work_struct *work) goto done; phytium_jpeg_init_regs(jpeg_dev); + /* It is evident that the host remains powered on during the + * resolution switch process, so restore the JPEG configuration. + */ + phytium_jpeg_write(jpeg_dev, BUF_LIST_INDEX_ADDR(VB_BUF_LAST), HAVE_SIGNAL); + jpeg_dev->once_poweroff = false; phytium_jpeg_get_resolution(jpeg_dev); + /* if source's resolution is changed, the event should be enqueued */ if (jpeg_dev->detected_timings.width != jpeg_dev->active_timings.width || jpeg_dev->detected_timings.height != jpeg_dev->active_timings.height || @@ -833,7 +854,7 @@ static void phytium_jpeg_resolution_work(struct work_struct *work) }; v4l2_event_queue(&jpeg_dev->vdev, &event); clear_bit(VIDEO_FRAME_INPRG, &jpeg_dev->status); - dev_info(jpeg_dev->dev, "event notifies changing resolution\n"); + dev_info(jpeg_dev->dev, "event notifies changing resolution.\n"); } else if (test_bit(VIDEO_STREAMING, &jpeg_dev->status)) { /* No resolution change so just restart streaming */ dev_info(jpeg_dev->dev, "resolution doesn't change\n"); @@ -1178,7 +1199,7 @@ static int phytium_jpeg_parser_timer30_irq(struct phytium_jpeg_dev *jpeg_dev) } ret = devm_request_irq(dev, irq, phytium_jpeg_timer30_irq, - IRQF_TIMER, PHYTIUM_JPEG_NAME, jpeg_dev); + IRQF_TIMER, PHYTIUM_JPEG_NAME, jpeg_dev); if (ret < 0) dev_err(dev, "Failed to request timer30 IRQ %d\n", irq); @@ -1231,7 +1252,8 @@ static int phytium_jpeg_init(struct phytium_jpeg_dev *jpeg_dev) dev_err(dev, "Failed to set DMA mask\n"); return ret; } - + /* Initialize the value of buffer_list_address15 register to identify having signal */ + phytium_jpeg_write(jpeg_dev, BUF_LIST_INDEX_ADDR(VB_BUF_LAST), HAVE_SIGNAL); /* Initializing JPEG Y and CbCr quantization table */ phytium_jpeg_init_jpeg_quant(jpeg_dev); @@ -1287,6 +1309,7 @@ static int phytium_jpeg_setup_video(struct phytium_jpeg_dev *jpeg_dev) jpeg_dev->pix_fmt.colorspace = V4L2_COLORSPACE_SRGB; /* maybe ARGB */ jpeg_dev->pix_fmt.quantization = V4L2_QUANTIZATION_FULL_RANGE; jpeg_dev->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; + jpeg_dev->once_poweroff = false; ret = v4l2_device_register(jpeg_dev->dev, v4l2_dev); if (ret != 0) { diff --git a/drivers/media/platform/phytium/phytium_jpeg_core.h b/drivers/media/platform/phytium/phytium_jpeg_core.h index a03ced5a0f6d3..6b291f23dd0fc 100644 --- a/drivers/media/platform/phytium/phytium_jpeg_core.h +++ b/drivers/media/platform/phytium/phytium_jpeg_core.h @@ -46,13 +46,17 @@ #define MAX_PIXEL_CLOCK (1920 * 1080 * 60) /* 1920 x 1080 x 60Hz */ #define SOURCE_RESOLUTION_DETECT_TIMEOUT msecs_to_jiffies(500) -#define RESOLUTION_CHANGE_DELAY msecs_to_jiffies(250) +#define RESOLUTION_CHANGE_DELAY msecs_to_jiffies(150) #define INVALID_RESOLUTION_DELAY msecs_to_jiffies(250) #define STOP_TIMEOUT msecs_to_jiffies(1000) #define INVALID_RESOLUTION_RETRIES 2 #define CAPTURE_BUF_NUMBER 3 /* using how many buffers */ #define VB_BUF_NO 0 /* there are 16 buffer, use which one */ +#define VB_BUF_LAST 15 /* Use the last one to identify no signal */ +#define HAVE_SIGNAL 0xCDDCDCCD /* VGA output signal */ +#define HOST_POWER_ON 0x0 /* Host is poweron */ +#define HOST_POWER_OFF 0xDEADBEEF /* Host is poweroff */ /* The below macros are defined for the JPEG header of the phytium JPEG Engine */ #define PHYTIUM_JPEG_HEADER_LEN (256 * 3) @@ -123,13 +127,14 @@ struct phytium_jpeg_dev { unsigned int sequence; unsigned int max_compressed_size; struct phytium_jpeg_addr src_addrs[OCM_BUF_NUM]; - struct phytium_jpeg_addr dst_addrs[16]; + struct phytium_jpeg_addr dst_addrs[VB_BUF_LAST + 1]; bool yuv420; unsigned int frame_rate; void __iomem *timer30_addr; void __iomem *timer31_addr; struct v4l2_ctrl_handler ctrl_handler; + bool once_poweroff; }; struct phytium_jpeg_config {