| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * Copyright (c) 2019 Amlogic, Inc. All rights reserved. |
| */ |
| |
| /* Linux Headers */ |
| #include <linux/kernel.h> |
| #include <linux/spinlock.h> |
| #include <linux/errno.h> |
| #include <linux/slab.h> |
| |
| /* Local Headers */ |
| #include <linux/amlogic/media/vout/vout_notify.h> |
| |
| /* Local Headers */ |
| #include "osd_hw.h" |
| #include "osd_io.h" |
| #include "osd_reg.h" |
| #include "osd_prot.h" |
| |
| int osd_set_prot(unsigned char x_rev, |
| unsigned char y_rev, |
| unsigned char bytes_per_pixel, |
| unsigned char conv_422to444, |
| unsigned char little_endian, |
| unsigned int hold_lines, |
| unsigned int x_start, |
| unsigned int x_end, |
| unsigned int y_start, |
| unsigned int y_end, |
| unsigned int y_len_m1, |
| unsigned char y_step, |
| unsigned char pat_start_ptr, |
| unsigned char pat_end_ptr, |
| unsigned long pat_val, |
| unsigned int canv_addr, |
| unsigned int cid_val, |
| unsigned char cid_mode, |
| unsigned char cugt, |
| unsigned char req_onoff_en, |
| unsigned int req_on_max, |
| unsigned int req_off_min, |
| unsigned char osd_index, |
| unsigned char on) |
| { |
| unsigned long data32; |
| |
| if (!on) { |
| /* no one use prot1. */ |
| VSYNCOSD_CLR_MPEG_REG_MASK(VPU_PROT1_MMC_CTRL, 0xf << 12); |
| VSYNCOSD_CLR_MPEG_REG_MASK(VPU_PROT1_CLK_GATE, 1 << 0); |
| if (osd_index == OSD1) { |
| /* switch back to little endian */ |
| VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD1_BLK0_CFG_W0, |
| 1, 15, 1); |
| VSYNCOSD_WR_MPEG_REG(VIU_OSD1_PROT_CTRL, 0); |
| } else if (osd_index == OSD2) { |
| /* switch back to little endian */ |
| VSYNCOSD_WR_MPEG_REG_BITS(VIU_OSD2_BLK0_CFG_W0, |
| 1, 15, 1); |
| VSYNCOSD_WR_MPEG_REG(VIU_OSD2_PROT_CTRL, 0); |
| } |
| return 0; |
| } |
| if (osd_index == OSD1) { |
| /* bit[12..15] OSD1 OSD2 OSD3 OSD4 */ |
| VSYNCOSD_WR_MPEG_REG_BITS(VPU_PROT1_MMC_CTRL, 1, 12, 4); |
| VSYNCOSD_WR_MPEG_REG(VIU_OSD1_PROT_CTRL, 1 << 15 | y_len_m1); |
| /* before rotate set big endian */ |
| VSYNCOSD_CLR_MPEG_REG_MASK(VIU_OSD1_BLK0_CFG_W0, 1 << 15); |
| } else if (osd_index == OSD2) { |
| VSYNCOSD_WR_MPEG_REG_BITS(VPU_PROT1_MMC_CTRL, 2, 12, 4); |
| /* bit[12..15] OSD1 OSD2 OSD3 OSD4 */ |
| VSYNCOSD_WR_MPEG_REG(VIU_OSD2_PROT_CTRL, 1 << 15 | y_len_m1); |
| /* before rotate set big endian */ |
| VSYNCOSD_CLR_MPEG_REG_MASK(VIU_OSD2_BLK0_CFG_W0, 1 << 15); |
| } |
| data32 = (x_end << 16) | |
| (x_start << 0); |
| VSYNCOSD_WR_MPEG_REG(VPU_PROT1_X_START_END, data32); |
| data32 = (y_end << 16) | |
| (y_start << 0); |
| VSYNCOSD_WR_MPEG_REG(VPU_PROT1_Y_START_END, data32); |
| data32 = (y_step << 16) | |
| (y_len_m1 << 0); |
| VSYNCOSD_WR_MPEG_REG(VPU_PROT1_Y_LEN_STEP, data32); |
| data32 = (pat_start_ptr << 4) | |
| (pat_end_ptr << 0); |
| VSYNCOSD_WR_MPEG_REG(VPU_PROT1_RPT_LOOP, data32); |
| VSYNCOSD_WR_MPEG_REG(VPU_PROT1_RPT_PAT, pat_val); |
| data32 = (cugt << 20) | |
| (cid_mode << 16) | |
| (cid_val << 8) | |
| (canv_addr << 0); |
| VSYNCOSD_WR_MPEG_REG(VPU_PROT1_DDR, data32); |
| data32 = (hold_lines << 8) | |
| (little_endian << 7) | |
| (conv_422to444 << 6) | |
| (bytes_per_pixel << 4) | |
| (y_rev << 3) | |
| (x_rev << 2) | |
| (1 << |
| 0); |
| /* [1:0] req_en: 0=Idle; 1=Rotate mode; 2=FIFO mode. */ |
| VSYNCOSD_WR_MPEG_REG(VPU_PROT1_GEN_CNTL, data32); |
| data32 = (req_onoff_en << 31) | |
| (req_off_min << 16) | |
| (req_on_max << 0); |
| VSYNCOSD_WR_MPEG_REG(VPU_PROT1_REQ_ONOFF, data32); |
| /* Enable clock */ |
| VSYNCOSD_WR_MPEG_REG(VPU_PROT1_CLK_GATE, 1); |
| return 0; |
| } |