^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/dmaengine.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/console.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/mutex.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/dma/ipu-dma.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/backlight.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/platform_data/dma-imx.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/platform_data/video-mx3fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define MX3FB_NAME "mx3_sdc_fb"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define MX3FB_REG_OFFSET 0xB4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /* SDC Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define SDC_COM_CONF (0xB4 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define SDC_GW_CTRL (0xB8 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define SDC_FG_POS (0xBC - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define SDC_BG_POS (0xC0 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define SDC_CUR_POS (0xC4 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define SDC_PWM_CTRL (0xC8 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define SDC_CUR_MAP (0xCC - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define SDC_HOR_CONF (0xD0 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define SDC_VER_CONF (0xD4 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define SDC_SHARP_CONF_1 (0xD8 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define SDC_SHARP_CONF_2 (0xDC - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /* Register bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define SDC_COM_TFT_COLOR 0x00000001UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define SDC_COM_FG_EN 0x00000010UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define SDC_COM_GWSEL 0x00000020UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define SDC_COM_GLB_A 0x00000040UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define SDC_COM_KEY_COLOR_G 0x00000080UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define SDC_COM_BG_EN 0x00000200UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define SDC_COM_SHARP 0x00001000UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) #define SDC_V_SYNC_WIDTH_L 0x00000001UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* Display Interface registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define DI_DISP_IF_CONF (0x0124 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define DI_DISP_SIG_POL (0x0128 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define DI_SER_DISP1_CONF (0x012C - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define DI_SER_DISP2_CONF (0x0130 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define DI_HSP_CLK_PER (0x0134 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define DI_DISP0_TIME_CONF_1 (0x0138 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define DI_DISP0_TIME_CONF_2 (0x013C - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #define DI_DISP0_TIME_CONF_3 (0x0140 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #define DI_DISP1_TIME_CONF_1 (0x0144 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define DI_DISP1_TIME_CONF_2 (0x0148 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define DI_DISP1_TIME_CONF_3 (0x014C - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define DI_DISP2_TIME_CONF_1 (0x0150 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define DI_DISP2_TIME_CONF_2 (0x0154 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define DI_DISP2_TIME_CONF_3 (0x0158 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define DI_DISP3_TIME_CONF (0x015C - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define DI_DISP0_DB0_MAP (0x0160 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define DI_DISP0_DB1_MAP (0x0164 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define DI_DISP0_DB2_MAP (0x0168 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define DI_DISP0_CB0_MAP (0x016C - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define DI_DISP0_CB1_MAP (0x0170 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define DI_DISP0_CB2_MAP (0x0174 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define DI_DISP1_DB0_MAP (0x0178 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define DI_DISP1_DB1_MAP (0x017C - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define DI_DISP1_DB2_MAP (0x0180 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define DI_DISP1_CB0_MAP (0x0184 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define DI_DISP1_CB1_MAP (0x0188 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define DI_DISP1_CB2_MAP (0x018C - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) #define DI_DISP2_DB0_MAP (0x0190 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #define DI_DISP2_DB1_MAP (0x0194 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define DI_DISP2_DB2_MAP (0x0198 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define DI_DISP2_CB0_MAP (0x019C - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define DI_DISP2_CB1_MAP (0x01A0 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define DI_DISP2_CB2_MAP (0x01A4 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) #define DI_DISP3_B0_MAP (0x01A8 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #define DI_DISP3_B1_MAP (0x01AC - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #define DI_DISP3_B2_MAP (0x01B0 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #define DI_DISP_ACC_CC (0x01B4 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define DI_DISP_LLA_CONF (0x01B8 - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define DI_DISP_LLA_DATA (0x01BC - MX3FB_REG_OFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /* DI_DISP_SIG_POL bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define DI_D3_VSYNC_POL_SHIFT 28
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #define DI_D3_HSYNC_POL_SHIFT 27
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #define DI_D3_DRDY_SHARP_POL_SHIFT 26
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #define DI_D3_CLK_POL_SHIFT 25
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define DI_D3_DATA_POL_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* DI_DISP_IF_CONF bits */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define DI_D3_CLK_IDLE_SHIFT 26
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) #define DI_D3_CLK_SEL_SHIFT 25
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) #define DI_D3_DATAMSK_SHIFT 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) enum ipu_panel {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) IPU_PANEL_SHARP_TFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) IPU_PANEL_TFT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) struct ipu_di_signal_cfg {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) unsigned datamask_en:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) unsigned clksel_en:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) unsigned clkidle_en:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) unsigned data_pol:1; /* true = inverted */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) unsigned clk_pol:1; /* true = rising edge */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) unsigned enable_pol:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) unsigned Hsync_pol:1; /* true = active high */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) unsigned Vsync_pol:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static const struct fb_videomode mx3fb_modedb[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* 240x320 @ 60 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) .name = "Sharp-QVGA",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) .refresh = 60,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) .xres = 240,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) .yres = 320,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) .pixclock = 185925,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .left_margin = 9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) .right_margin = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) .upper_margin = 7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .lower_margin = 9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) .hsync_len = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) .vsync_len = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) FB_SYNC_CLK_INVERT | FB_SYNC_DATA_INVERT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) FB_SYNC_CLK_IDLE_EN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) .vmode = FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) .flag = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) /* 240x33 @ 60 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) .name = "Sharp-CLI",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) .refresh = 60,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .xres = 240,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .yres = 33,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) .pixclock = 185925,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) .left_margin = 9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .right_margin = 16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .upper_margin = 7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) .lower_margin = 9 + 287,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) .hsync_len = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .vsync_len = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) FB_SYNC_CLK_INVERT | FB_SYNC_DATA_INVERT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) FB_SYNC_CLK_IDLE_EN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .vmode = FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .flag = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /* 640x480 @ 60 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .name = "NEC-VGA",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .refresh = 60,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) .xres = 640,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) .yres = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .pixclock = 38255,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .left_margin = 144,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) .right_margin = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) .upper_margin = 34,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .lower_margin = 40,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .hsync_len = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .vsync_len = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) .vmode = FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) .flag = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) /* NTSC TV output */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) .name = "TV-NTSC",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) .refresh = 60,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) .xres = 640,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) .yres = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) .pixclock = 37538,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) .left_margin = 38,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .right_margin = 858 - 640 - 38 - 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .upper_margin = 36,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .lower_margin = 518 - 480 - 36 - 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) .hsync_len = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) .vsync_len = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) .sync = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) .vmode = FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .flag = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) /* PAL TV output */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) .name = "TV-PAL",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) .refresh = 50,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) .xres = 640,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) .yres = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) .pixclock = 37538,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) .left_margin = 38,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) .right_margin = 960 - 640 - 38 - 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) .upper_margin = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) .lower_margin = 555 - 480 - 32 - 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) .hsync_len = 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) .vsync_len = 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) .sync = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) .vmode = FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) .flag = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) /* TV output VGA mode, 640x480 @ 65 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) .name = "TV-VGA",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) .refresh = 60,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) .xres = 640,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) .yres = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) .pixclock = 40574,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) .left_margin = 35,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) .right_margin = 45,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) .upper_margin = 9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) .lower_margin = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) .hsync_len = 46,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) .vsync_len = 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) .sync = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) .vmode = FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) .flag = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) struct mx3fb_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) struct fb_info *fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) int backlight_level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) void __iomem *reg_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) spinlock_t lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct backlight_device *bl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) uint32_t h_start_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) uint32_t v_start_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) enum disp_data_mapping disp_data_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) struct dma_chan_request {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) struct mx3fb_data *mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) enum ipu_channel id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) /* MX3 specific framebuffer information. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) struct mx3fb_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) int blank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) enum ipu_channel ipu_ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) uint32_t cur_ipu_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) u32 pseudo_palette[16];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) struct completion flip_cmpl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) struct mutex mutex; /* Protects fb-ops */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) struct mx3fb_data *mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) struct idmac_channel *idmac_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) struct dma_async_tx_descriptor *txd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) dma_cookie_t cookie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct scatterlist sg[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) struct fb_var_screeninfo cur_var; /* current var info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static void sdc_set_brightness(struct mx3fb_data *mx3fb, uint8_t value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) static u32 sdc_get_brightness(struct mx3fb_data *mx3fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) static int mx3fb_bl_get_brightness(struct backlight_device *bl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) struct mx3fb_data *fbd = bl_get_data(bl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) return sdc_get_brightness(fbd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) static int mx3fb_bl_update_status(struct backlight_device *bl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) struct mx3fb_data *fbd = bl_get_data(bl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) int brightness = bl->props.brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (bl->props.power != FB_BLANK_UNBLANK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) brightness = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (bl->props.fb_blank != FB_BLANK_UNBLANK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) brightness = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) fbd->backlight_level = (fbd->backlight_level & ~0xFF) | brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) sdc_set_brightness(fbd, fbd->backlight_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) static const struct backlight_ops mx3fb_lcdc_bl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) .update_status = mx3fb_bl_update_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) .get_brightness = mx3fb_bl_get_brightness,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) static void mx3fb_init_backlight(struct mx3fb_data *fbd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) struct backlight_properties props;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) struct backlight_device *bl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if (fbd->bl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) memset(&props, 0, sizeof(struct backlight_properties));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) props.max_brightness = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) props.type = BACKLIGHT_RAW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) sdc_set_brightness(fbd, fbd->backlight_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) bl = backlight_device_register("mx3fb-bl", fbd->dev, fbd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) &mx3fb_lcdc_bl_ops, &props);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (IS_ERR(bl)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) dev_err(fbd->dev, "error %ld on backlight register\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) PTR_ERR(bl));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) fbd->bl = bl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) bl->props.power = FB_BLANK_UNBLANK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) bl->props.fb_blank = FB_BLANK_UNBLANK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) bl->props.brightness = mx3fb_bl_get_brightness(bl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) static void mx3fb_exit_backlight(struct mx3fb_data *fbd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) backlight_device_unregister(fbd->bl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static void mx3fb_dma_done(void *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) /* Used fb-mode and bpp. Can be set on kernel command line, therefore file-static. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) static const char *fb_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) static unsigned long default_bpp = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) static u32 mx3fb_read_reg(struct mx3fb_data *mx3fb, unsigned long reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) return __raw_readl(mx3fb->reg_base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) static void mx3fb_write_reg(struct mx3fb_data *mx3fb, u32 value, unsigned long reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) __raw_writel(value, mx3fb->reg_base + reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) struct di_mapping {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) uint32_t b0, b1, b2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) static const struct di_mapping di_mappings[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) [IPU_DISP_DATA_MAPPING_RGB666] = { 0x0005000f, 0x000b000f, 0x0011000f },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) [IPU_DISP_DATA_MAPPING_RGB565] = { 0x0004003f, 0x000a000f, 0x000f003f },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) [IPU_DISP_DATA_MAPPING_RGB888] = { 0x00070000, 0x000f0000, 0x00170000 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) static void sdc_fb_init(struct mx3fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) struct mx3fb_data *mx3fb = fbi->mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) uint32_t reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) mx3fb_write_reg(mx3fb, reg | SDC_COM_BG_EN, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /* Returns enabled flag before uninit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) static uint32_t sdc_fb_uninit(struct mx3fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) struct mx3fb_data *mx3fb = fbi->mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) uint32_t reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) mx3fb_write_reg(mx3fb, reg & ~SDC_COM_BG_EN, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) return reg & SDC_COM_BG_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) static void sdc_enable_channel(struct mx3fb_info *mx3_fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) struct idmac_channel *ichan = mx3_fbi->idmac_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) struct dma_chan *dma_chan = &ichan->dma_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) dma_cookie_t cookie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (mx3_fbi->txd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) dev_dbg(mx3fb->dev, "mx3fbi %p, desc %p, sg %p\n", mx3_fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) to_tx_desc(mx3_fbi->txd), to_tx_desc(mx3_fbi->txd)->sg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) dev_dbg(mx3fb->dev, "mx3fbi %p, txd = NULL\n", mx3_fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) /* This enables the channel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) if (mx3_fbi->cookie < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) mx3_fbi->txd = dmaengine_prep_slave_sg(dma_chan,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) &mx3_fbi->sg[0], 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (!mx3_fbi->txd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) dev_err(mx3fb->dev, "Cannot allocate descriptor on %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) dma_chan->chan_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) mx3_fbi->txd->callback_param = mx3_fbi->txd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) mx3_fbi->txd->callback = mx3fb_dma_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) cookie = mx3_fbi->txd->tx_submit(mx3_fbi->txd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) dev_dbg(mx3fb->dev, "%d: Submit %p #%d [%c]\n", __LINE__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) mx3_fbi->txd, cookie, list_empty(&ichan->queue) ? '-' : '+');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (!mx3_fbi->txd || !mx3_fbi->txd->tx_submit) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) dev_err(mx3fb->dev, "Cannot enable channel %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) dma_chan->chan_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) /* Just re-activate the same buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) dma_async_issue_pending(dma_chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) cookie = mx3_fbi->cookie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) dev_dbg(mx3fb->dev, "%d: Re-submit %p #%d [%c]\n", __LINE__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) mx3_fbi->txd, cookie, list_empty(&ichan->queue) ? '-' : '+');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) if (cookie >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) spin_lock_irqsave(&mx3fb->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) sdc_fb_init(mx3_fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) mx3_fbi->cookie = cookie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) spin_unlock_irqrestore(&mx3fb->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) * Attention! Without this msleep the channel keeps generating
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) * interrupts. Next sdc_set_brightness() is going to be called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) * from mx3fb_blank().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) msleep(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) static void sdc_disable_channel(struct mx3fb_info *mx3_fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) uint32_t enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) if (mx3_fbi->txd == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) spin_lock_irqsave(&mx3fb->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) enabled = sdc_fb_uninit(mx3_fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) spin_unlock_irqrestore(&mx3fb->lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) dmaengine_terminate_all(mx3_fbi->txd->chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) mx3_fbi->txd = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) mx3_fbi->cookie = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) * sdc_set_window_pos() - set window position of the respective plane.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) * @mx3fb: mx3fb context.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) * @channel: IPU DMAC channel ID.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) * @x_pos: X coordinate relative to the top left corner to place window at.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) * @y_pos: Y coordinate relative to the top left corner to place window at.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) * @return: 0 on success or negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) static int sdc_set_window_pos(struct mx3fb_data *mx3fb, enum ipu_channel channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) int16_t x_pos, int16_t y_pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) if (channel != IDMAC_SDC_0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) x_pos += mx3fb->h_start_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) y_pos += mx3fb->v_start_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) mx3fb_write_reg(mx3fb, (x_pos << 16) | y_pos, SDC_BG_POS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) * sdc_init_panel() - initialize a synchronous LCD panel.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) * @mx3fb: mx3fb context.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) * @panel: panel type.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) * @pixel_clk: desired pixel clock frequency in Hz.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) * @width: width of panel in pixels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) * @height: height of panel in pixels.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) * @h_start_width: number of pixel clocks between the HSYNC signal pulse
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) * and the start of valid data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) * @h_sync_width: width of the HSYNC signal in units of pixel clocks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) * @h_end_width: number of pixel clocks between the end of valid data
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) * and the HSYNC signal for next line.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) * @v_start_width: number of lines between the VSYNC signal pulse and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) * start of valid data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) * @v_sync_width: width of the VSYNC signal in units of lines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) * @v_end_width: number of lines between the end of valid data and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) * VSYNC signal for next frame.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) * @sig: bitfield of signal polarities for LCD interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) * @return: 0 on success or negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) static int sdc_init_panel(struct mx3fb_data *mx3fb, enum ipu_panel panel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) uint32_t pixel_clk,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) uint16_t width, uint16_t height,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) uint16_t h_start_width, uint16_t h_sync_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) uint16_t h_end_width, uint16_t v_start_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) uint16_t v_sync_width, uint16_t v_end_width,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) const struct ipu_di_signal_cfg *sig)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) unsigned long lock_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) uint32_t reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) uint32_t old_conf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) uint32_t div;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) struct clk *ipu_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) const struct di_mapping *map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) dev_dbg(mx3fb->dev, "panel size = %d x %d", width, height);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) if (v_sync_width == 0 || h_sync_width == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) /* Init panel size and blanking periods */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) reg = ((uint32_t) (h_sync_width - 1) << 26) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) ((uint32_t) (width + h_start_width + h_end_width - 1) << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) mx3fb_write_reg(mx3fb, reg, SDC_HOR_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) printk(KERN_CONT " hor_conf %x,", reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) reg = ((uint32_t) (v_sync_width - 1) << 26) | SDC_V_SYNC_WIDTH_L |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) ((uint32_t) (height + v_start_width + v_end_width - 1) << 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) mx3fb_write_reg(mx3fb, reg, SDC_VER_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) printk(KERN_CONT " ver_conf %x\n", reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) mx3fb->h_start_width = h_start_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) mx3fb->v_start_width = v_start_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) switch (panel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) case IPU_PANEL_SHARP_TFT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) mx3fb_write_reg(mx3fb, 0x00FD0102L, SDC_SHARP_CONF_1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) mx3fb_write_reg(mx3fb, 0x00F500F4L, SDC_SHARP_CONF_2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) mx3fb_write_reg(mx3fb, SDC_COM_SHARP | SDC_COM_TFT_COLOR, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) case IPU_PANEL_TFT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) mx3fb_write_reg(mx3fb, SDC_COM_TFT_COLOR, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) /* Init clocking */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) * Calculate divider: fractional part is 4 bits so simply multiple by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) * 2^4 to get fractional part, as long as we stay under ~250MHz and on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) * i.MX31 it (HSP_CLK) is <= 178MHz. Currently 128.267MHz
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) ipu_clk = clk_get(mx3fb->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) if (!IS_ERR(ipu_clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) div = clk_get_rate(ipu_clk) * 16 / pixel_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) clk_put(ipu_clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) div = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (div < 0x40) { /* Divider less than 4 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) dev_dbg(mx3fb->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) "InitPanel() - Pixel clock divider less than 4\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) div = 0x40;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) dev_dbg(mx3fb->dev, "pixel clk = %u, divider %u.%u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) pixel_clk, div >> 4, (div & 7) * 125);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) spin_lock_irqsave(&mx3fb->lock, lock_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) * DISP3_IF_CLK_DOWN_WR is half the divider value and 2 fraction bits
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) * fewer. Subtract 1 extra from DISP3_IF_CLK_DOWN_WR based on timing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) * debug. DISP3_IF_CLK_UP_WR is 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) mx3fb_write_reg(mx3fb, (((div / 8) - 1) << 22) | div, DI_DISP3_TIME_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) /* DI settings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) old_conf = mx3fb_read_reg(mx3fb, DI_DISP_IF_CONF) & 0x78FFFFFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) old_conf |= sig->datamask_en << DI_D3_DATAMSK_SHIFT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) sig->clksel_en << DI_D3_CLK_SEL_SHIFT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) sig->clkidle_en << DI_D3_CLK_IDLE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) mx3fb_write_reg(mx3fb, old_conf, DI_DISP_IF_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) old_conf = mx3fb_read_reg(mx3fb, DI_DISP_SIG_POL) & 0xE0FFFFFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) old_conf |= sig->data_pol << DI_D3_DATA_POL_SHIFT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) sig->clk_pol << DI_D3_CLK_POL_SHIFT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) sig->enable_pol << DI_D3_DRDY_SHARP_POL_SHIFT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) sig->Hsync_pol << DI_D3_HSYNC_POL_SHIFT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) sig->Vsync_pol << DI_D3_VSYNC_POL_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) mx3fb_write_reg(mx3fb, old_conf, DI_DISP_SIG_POL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) map = &di_mappings[mx3fb->disp_data_fmt];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) mx3fb_write_reg(mx3fb, map->b0, DI_DISP3_B0_MAP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) mx3fb_write_reg(mx3fb, map->b1, DI_DISP3_B1_MAP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) mx3fb_write_reg(mx3fb, map->b2, DI_DISP3_B2_MAP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) spin_unlock_irqrestore(&mx3fb->lock, lock_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) dev_dbg(mx3fb->dev, "DI_DISP_IF_CONF = 0x%08X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) mx3fb_read_reg(mx3fb, DI_DISP_IF_CONF));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) dev_dbg(mx3fb->dev, "DI_DISP_SIG_POL = 0x%08X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) mx3fb_read_reg(mx3fb, DI_DISP_SIG_POL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) dev_dbg(mx3fb->dev, "DI_DISP3_TIME_CONF = 0x%08X\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) mx3fb_read_reg(mx3fb, DI_DISP3_TIME_CONF));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) * sdc_set_color_key() - set the transparent color key for SDC graphic plane.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) * @mx3fb: mx3fb context.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) * @channel: IPU DMAC channel ID.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) * @enable: boolean to enable or disable color keyl.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) * @color_key: 24-bit RGB color to use as transparent color key.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) * @return: 0 on success or negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) static int sdc_set_color_key(struct mx3fb_data *mx3fb, enum ipu_channel channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) bool enable, uint32_t color_key)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) uint32_t reg, sdc_conf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) unsigned long lock_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) spin_lock_irqsave(&mx3fb->lock, lock_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) sdc_conf = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) if (channel == IDMAC_SDC_0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) sdc_conf &= ~SDC_COM_GWSEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) sdc_conf |= SDC_COM_GWSEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) if (enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) reg = mx3fb_read_reg(mx3fb, SDC_GW_CTRL) & 0xFF000000L;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) mx3fb_write_reg(mx3fb, reg | (color_key & 0x00FFFFFFL),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) SDC_GW_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) sdc_conf |= SDC_COM_KEY_COLOR_G;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) sdc_conf &= ~SDC_COM_KEY_COLOR_G;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) mx3fb_write_reg(mx3fb, sdc_conf, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) spin_unlock_irqrestore(&mx3fb->lock, lock_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) * sdc_set_global_alpha() - set global alpha blending modes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) * @mx3fb: mx3fb context.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) * @enable: boolean to enable or disable global alpha blending. If disabled,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) * per pixel blending is used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) * @alpha: global alpha value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * @return: 0 on success or negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) static int sdc_set_global_alpha(struct mx3fb_data *mx3fb, bool enable, uint8_t alpha)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) uint32_t reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) unsigned long lock_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) spin_lock_irqsave(&mx3fb->lock, lock_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) if (enable) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) reg = mx3fb_read_reg(mx3fb, SDC_GW_CTRL) & 0x00FFFFFFL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) mx3fb_write_reg(mx3fb, reg | ((uint32_t) alpha << 24), SDC_GW_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) mx3fb_write_reg(mx3fb, reg | SDC_COM_GLB_A, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) reg = mx3fb_read_reg(mx3fb, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) mx3fb_write_reg(mx3fb, reg & ~SDC_COM_GLB_A, SDC_COM_CONF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) spin_unlock_irqrestore(&mx3fb->lock, lock_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) static u32 sdc_get_brightness(struct mx3fb_data *mx3fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) u32 brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) brightness = mx3fb_read_reg(mx3fb, SDC_PWM_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) brightness = (brightness >> 16) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) return brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) static void sdc_set_brightness(struct mx3fb_data *mx3fb, uint8_t value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) dev_dbg(mx3fb->dev, "%s: value = %d\n", __func__, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) /* This might be board-specific */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) mx3fb_write_reg(mx3fb, 0x03000000UL | value << 16, SDC_PWM_CTRL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) static uint32_t bpp_to_pixfmt(int bpp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) uint32_t pixfmt = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) switch (bpp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) pixfmt = IPU_PIX_FMT_BGR24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) pixfmt = IPU_PIX_FMT_BGR32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) pixfmt = IPU_PIX_FMT_RGB565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) return pixfmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) static int mx3fb_blank(int blank, struct fb_info *fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) bool lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) static int mx3fb_unmap_video_memory(struct fb_info *fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) * mx3fb_set_fix() - set fixed framebuffer parameters from variable settings.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) * @info: framebuffer information pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) * @return: 0 on success or negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) static int mx3fb_set_fix(struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) struct fb_fix_screeninfo *fix = &fbi->fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) struct fb_var_screeninfo *var = &fbi->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) strncpy(fix->id, "DISP3 BG", 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) fix->type = FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) fix->accel = FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) fix->visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) fix->xpanstep = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) fix->ypanstep = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) static void mx3fb_dma_done(void *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) struct idmac_tx_desc *tx_desc = to_tx_desc(arg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) struct dma_chan *chan = tx_desc->txd.chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) struct idmac_channel *ichannel = to_idmac_chan(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) struct mx3fb_data *mx3fb = ichannel->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) dev_dbg(mx3fb->dev, "irq %d callback\n", ichannel->eof_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) /* We only need one interrupt, it will be re-enabled as needed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) disable_irq_nosync(ichannel->eof_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) complete(&mx3_fbi->flip_cmpl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) static bool mx3fb_must_set_par(struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) struct mx3fb_info *mx3_fbi = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) struct fb_var_screeninfo old_var = mx3_fbi->cur_var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) struct fb_var_screeninfo new_var = fbi->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if ((fbi->var.activate & FB_ACTIVATE_FORCE) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) (fbi->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) * Ignore xoffset and yoffset update,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) * because pan display handles this case.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) old_var.xoffset = new_var.xoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) old_var.yoffset = new_var.yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) return !!memcmp(&old_var, &new_var, sizeof(struct fb_var_screeninfo));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) static int __set_par(struct fb_info *fbi, bool lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) u32 mem_len, cur_xoffset, cur_yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) struct ipu_di_signal_cfg sig_cfg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) enum ipu_panel mode = IPU_PANEL_TFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) struct mx3fb_info *mx3_fbi = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) struct idmac_channel *ichan = mx3_fbi->idmac_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) struct idmac_video_param *video = &ichan->params.video;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) struct scatterlist *sg = mx3_fbi->sg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) /* Total cleanup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) if (mx3_fbi->txd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) sdc_disable_channel(mx3_fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) mx3fb_set_fix(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) mem_len = fbi->var.yres_virtual * fbi->fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) if (mem_len > fbi->fix.smem_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) if (fbi->fix.smem_start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) mx3fb_unmap_video_memory(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) if (mx3fb_map_video_memory(fbi, mem_len, lock) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) sg_init_table(&sg[0], 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) sg_init_table(&sg[1], 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) sg_dma_address(&sg[0]) = fbi->fix.smem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) sg_set_page(&sg[0], virt_to_page(fbi->screen_base),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) fbi->fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) offset_in_page(fbi->screen_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) if (mx3_fbi->ipu_ch == IDMAC_SDC_0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) memset(&sig_cfg, 0, sizeof(sig_cfg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) sig_cfg.Hsync_pol = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) sig_cfg.Vsync_pol = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) if (fbi->var.sync & FB_SYNC_CLK_INVERT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) sig_cfg.clk_pol = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) if (fbi->var.sync & FB_SYNC_DATA_INVERT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) sig_cfg.data_pol = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if (fbi->var.sync & FB_SYNC_OE_ACT_HIGH)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) sig_cfg.enable_pol = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) sig_cfg.clkidle_en = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) if (fbi->var.sync & FB_SYNC_CLK_SEL_EN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) sig_cfg.clksel_en = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (fbi->var.sync & FB_SYNC_SHARP_MODE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) mode = IPU_PANEL_SHARP_TFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) dev_dbg(fbi->device, "pixclock = %u Hz\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) (u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if (sdc_init_panel(mx3fb, mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) (PICOS2KHZ(fbi->var.pixclock)) * 1000UL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) fbi->var.xres, fbi->var.yres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) fbi->var.left_margin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) fbi->var.hsync_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) fbi->var.right_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) fbi->var.hsync_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) fbi->var.upper_margin,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) fbi->var.vsync_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) fbi->var.lower_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) fbi->var.vsync_len, &sig_cfg) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) dev_err(fbi->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) "mx3fb: Error initializing panel.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) sdc_set_window_pos(mx3fb, mx3_fbi->ipu_ch, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) mx3_fbi->cur_ipu_buf = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) video->out_pixel_fmt = bpp_to_pixfmt(fbi->var.bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) video->out_width = fbi->var.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) video->out_height = fbi->var.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) video->out_stride = fbi->var.xres_virtual;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) if (mx3_fbi->blank == FB_BLANK_UNBLANK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) sdc_enable_channel(mx3_fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) * sg[0] points to fb smem_start address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) * and is actually active in controller.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) mx3_fbi->cur_var.xoffset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) mx3_fbi->cur_var.yoffset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) * Preserve xoffset and yoffest in case they are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) * inactive in controller as fb is blanked.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) cur_xoffset = mx3_fbi->cur_var.xoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) cur_yoffset = mx3_fbi->cur_var.yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) mx3_fbi->cur_var = fbi->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) mx3_fbi->cur_var.xoffset = cur_xoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) mx3_fbi->cur_var.yoffset = cur_yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) * mx3fb_set_par() - set framebuffer parameters and change the operating mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) * @fbi: framebuffer information pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) * @return: 0 on success or negative error code on failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) static int mx3fb_set_par(struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) struct mx3fb_info *mx3_fbi = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) struct idmac_channel *ichan = mx3_fbi->idmac_channel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) dev_dbg(mx3fb->dev, "%s [%c]\n", __func__, list_empty(&ichan->queue) ? '-' : '+');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) mutex_lock(&mx3_fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) ret = mx3fb_must_set_par(fbi) ? __set_par(fbi, true) : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) mutex_unlock(&mx3_fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) * mx3fb_check_var() - check and adjust framebuffer variable parameters.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) * @var: framebuffer variable parameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) * @fbi: framebuffer information pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) static int mx3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) struct mx3fb_info *mx3_fbi = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) u32 vtotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) u32 htotal;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) dev_dbg(fbi->device, "%s\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) if (var->xres_virtual < var->xres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) var->xres_virtual = var->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) if (var->yres_virtual < var->yres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) var->yres_virtual = var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) (var->bits_per_pixel != 16))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) var->bits_per_pixel = default_bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) var->red.offset = 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) var->red.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) var->green.length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) var->green.offset = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) var->green.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) var->blue.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) var->transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) var->transp.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) var->red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) var->red.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) var->green.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) var->blue.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) var->transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) var->transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) var->transp.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) var->red.offset = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) var->red.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) var->green.offset = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) var->green.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) var->blue.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) var->transp.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) var->transp.offset = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) var->transp.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) if (var->pixclock < 1000) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) htotal = var->xres + var->right_margin + var->hsync_len +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) var->left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) vtotal = var->yres + var->lower_margin + var->vsync_len +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) var->upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) var->pixclock = (vtotal * htotal * 6UL) / 100UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) var->pixclock = KHZ2PICOS(var->pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) dev_dbg(fbi->device, "pixclock set for 60Hz refresh = %u ps\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) var->pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) var->height = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) var->width = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) var->grayscale = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) /* Preserve sync flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) var->sync |= mx3_fbi->cur_var.sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) mx3_fbi->cur_var.sync |= var->sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) static u32 chan_to_field(unsigned int chan, struct fb_bitfield *bf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) chan &= 0xffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) chan >>= 16 - bf->length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) return chan << bf->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) static int mx3fb_setcolreg(unsigned int regno, unsigned int red,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) unsigned int green, unsigned int blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) unsigned int trans, struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) struct mx3fb_info *mx3_fbi = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) int ret = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) dev_dbg(fbi->device, "%s, regno = %u\n", __func__, regno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) mutex_lock(&mx3_fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) * If greyscale is true, then we convert the RGB value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) * to greyscale no matter what visual we are using.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) if (fbi->var.grayscale)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) red = green = blue = (19595 * red + 38470 * green +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) 7471 * blue) >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) switch (fbi->fix.visual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) case FB_VISUAL_TRUECOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) * 16-bit True Colour. We encode the RGB value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) * according to the RGB bitfield information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) if (regno < 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) u32 *pal = fbi->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) val = chan_to_field(red, &fbi->var.red);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) val |= chan_to_field(green, &fbi->var.green);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) val |= chan_to_field(blue, &fbi->var.blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) pal[regno] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) case FB_VISUAL_STATIC_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) case FB_VISUAL_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) mutex_unlock(&mx3_fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) static void __blank(int blank, struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) struct mx3fb_info *mx3_fbi = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) struct mx3fb_data *mx3fb = mx3_fbi->mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) int was_blank = mx3_fbi->blank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) mx3_fbi->blank = blank;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) /* Attention!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) * Do not call sdc_disable_channel() for a channel that is disabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) * already! This will result in a kernel NULL pointer dereference
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) * (mx3_fbi->txd is NULL). Hide the fact, that all blank modes are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) * handled equally by this driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) if (blank > FB_BLANK_UNBLANK && was_blank > FB_BLANK_UNBLANK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) switch (blank) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) case FB_BLANK_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) case FB_BLANK_VSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) case FB_BLANK_HSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) case FB_BLANK_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) sdc_set_brightness(mx3fb, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) /* Give LCD time to update - enough for 50 and 60 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) msleep(25);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) sdc_disable_channel(mx3_fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) case FB_BLANK_UNBLANK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) sdc_enable_channel(mx3_fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) sdc_set_brightness(mx3fb, mx3fb->backlight_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) * mx3fb_blank() - blank the display.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) static int mx3fb_blank(int blank, struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) struct mx3fb_info *mx3_fbi = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) dev_dbg(fbi->device, "%s, blank = %d, base %p, len %u\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) blank, fbi->screen_base, fbi->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) if (mx3_fbi->blank == blank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) mutex_lock(&mx3_fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) __blank(blank, fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) mutex_unlock(&mx3_fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) * mx3fb_pan_display() - pan or wrap the display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) * @var: variable screen buffer information.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) * @info: framebuffer information pointer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) * We look only at xoffset, yoffset and the FB_VMODE_YWRAP flag
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) static int mx3fb_pan_display(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) struct mx3fb_info *mx3_fbi = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) u32 y_bottom;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) unsigned long base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) off_t offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) dma_cookie_t cookie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) struct scatterlist *sg = mx3_fbi->sg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) struct dma_chan *dma_chan = &mx3_fbi->idmac_channel->dma_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) struct dma_async_tx_descriptor *txd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) dev_dbg(fbi->device, "%s [%c]\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) list_empty(&mx3_fbi->idmac_channel->queue) ? '-' : '+');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) if (var->xoffset > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) dev_dbg(fbi->device, "x panning not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) if (mx3_fbi->cur_var.xoffset == var->xoffset &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) mx3_fbi->cur_var.yoffset == var->yoffset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) return 0; /* No change, do nothing */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) y_bottom = var->yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) if (!(var->vmode & FB_VMODE_YWRAP))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) y_bottom += fbi->var.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) if (y_bottom > fbi->var.yres_virtual)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) mutex_lock(&mx3_fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) offset = var->yoffset * fbi->fix.line_length
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) + var->xoffset * (fbi->var.bits_per_pixel / 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) base = fbi->fix.smem_start + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) dev_dbg(fbi->device, "Updating SDC BG buf %d address=0x%08lX\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) mx3_fbi->cur_ipu_buf, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) * We enable the End of Frame interrupt, which will free a tx-descriptor,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) * which we will need for the next dmaengine_prep_slave_sg(). The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) * IRQ-handler will disable the IRQ again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) init_completion(&mx3_fbi->flip_cmpl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) enable_irq(mx3_fbi->idmac_channel->eof_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) ret = wait_for_completion_timeout(&mx3_fbi->flip_cmpl, HZ / 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) if (ret <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) mutex_unlock(&mx3_fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) dev_info(fbi->device, "Panning failed due to %s\n", ret < 0 ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) "user interrupt" : "timeout");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) disable_irq(mx3_fbi->idmac_channel->eof_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) return ret ? : -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) mx3_fbi->cur_ipu_buf = !mx3_fbi->cur_ipu_buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) sg_dma_address(&sg[mx3_fbi->cur_ipu_buf]) = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) sg_set_page(&sg[mx3_fbi->cur_ipu_buf],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) virt_to_page(fbi->screen_base + offset), fbi->fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) offset_in_page(fbi->screen_base + offset));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) if (mx3_fbi->txd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) async_tx_ack(mx3_fbi->txd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) txd = dmaengine_prep_slave_sg(dma_chan, sg +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) mx3_fbi->cur_ipu_buf, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) if (!txd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) dev_err(fbi->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) "Error preparing a DMA transaction descriptor.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) mutex_unlock(&mx3_fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) txd->callback_param = txd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) txd->callback = mx3fb_dma_done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) * Emulate original mx3fb behaviour: each new call to idmac_tx_submit()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) * should switch to another buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) cookie = txd->tx_submit(txd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) dev_dbg(fbi->device, "%d: Submit %p #%d\n", __LINE__, txd, cookie);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) if (cookie < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) dev_err(fbi->device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) "Error updating SDC buf %d to address=0x%08lX\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) mx3_fbi->cur_ipu_buf, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) mutex_unlock(&mx3_fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) mx3_fbi->txd = txd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) fbi->var.xoffset = var->xoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) fbi->var.yoffset = var->yoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) if (var->vmode & FB_VMODE_YWRAP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) fbi->var.vmode |= FB_VMODE_YWRAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) fbi->var.vmode &= ~FB_VMODE_YWRAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) mx3_fbi->cur_var = fbi->var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) mutex_unlock(&mx3_fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242) dev_dbg(fbi->device, "Update complete\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) * This structure contains the pointers to the control functions that are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) * invoked by the core framebuffer driver to perform operations like
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250) * blitting, rectangle filling, copy regions and cursor definition.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) static const struct fb_ops mx3fb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) .fb_set_par = mx3fb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) .fb_check_var = mx3fb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) .fb_setcolreg = mx3fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) .fb_pan_display = mx3fb_pan_display,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258) .fb_fillrect = cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) .fb_copyarea = cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) .fb_imageblit = cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) .fb_blank = mx3fb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) #ifdef CONFIG_PM
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) * Power management hooks. Note that we won't be called from IRQ context,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) * unlike the blank functions above, so we may sleep.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) * Suspends the framebuffer and blanks the screen. Power management support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) static int mx3fb_suspend(struct platform_device *pdev, pm_message_t state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) struct mx3fb_data *mx3fb = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) fb_set_suspend(mx3fb->fbi, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) if (mx3_fbi->blank == FB_BLANK_UNBLANK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) sdc_disable_channel(mx3_fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) sdc_set_brightness(mx3fb, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) * Resumes the framebuffer and unblanks the screen. Power management support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) static int mx3fb_resume(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) struct mx3fb_data *mx3fb = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) struct mx3fb_info *mx3_fbi = mx3fb->fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) if (mx3_fbi->blank == FB_BLANK_UNBLANK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) sdc_enable_channel(mx3_fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) sdc_set_brightness(mx3fb, mx3fb->backlight_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) console_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) fb_set_suspend(mx3fb->fbi, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) console_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) #define mx3fb_suspend NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) #define mx3fb_resume NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) * Main framebuffer functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319) * mx3fb_map_video_memory() - allocates the DRAM memory for the frame buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) * @fbi: framebuffer information pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) * @mem_len: length of mapped memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) * @lock: do not lock during initialisation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) * @return: Error code indicating success or failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) * This buffer is remapped into a non-cached, non-buffered, memory region to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) * allow palette and pixel writes to occur without flushing the cache. Once this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327) * area is remapped, all virtual memory access to the video memory should occur
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) * at the new region.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) static int mx3fb_map_video_memory(struct fb_info *fbi, unsigned int mem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) bool lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) int retval = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) dma_addr_t addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336) fbi->screen_base = dma_alloc_wc(fbi->device, mem_len, &addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) GFP_DMA | GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) if (!fbi->screen_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) mem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342) retval = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) goto err0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) if (lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) mutex_lock(&fbi->mm_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348) fbi->fix.smem_start = addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) fbi->fix.smem_len = mem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) if (lock)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) mutex_unlock(&fbi->mm_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) (uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) fbi->screen_size = fbi->fix.smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358) /* Clear the screen */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) err0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364) fbi->fix.smem_len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) fbi->fix.smem_start = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) fbi->screen_base = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371) * mx3fb_unmap_video_memory() - de-allocate frame buffer memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) * @fbi: framebuffer information pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) * @return: error code indicating success or failure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) static int mx3fb_unmap_video_memory(struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377) dma_free_wc(fbi->device, fbi->fix.smem_len, fbi->screen_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) fbi->fix.smem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) fbi->screen_base = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) mutex_lock(&fbi->mm_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) fbi->fix.smem_start = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) fbi->fix.smem_len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) mutex_unlock(&fbi->mm_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389) * mx3fb_init_fbinfo() - initialize framebuffer information object.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) * @return: initialized framebuffer structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392) static struct fb_info *mx3fb_init_fbinfo(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) const struct fb_ops *ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) struct fb_info *fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) struct mx3fb_info *mx3fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) /* Allocate sufficient memory for the fb structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) fbi = framebuffer_alloc(sizeof(struct mx3fb_info), dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) if (!fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) mx3fbi = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) mx3fbi->cookie = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) mx3fbi->cur_ipu_buf = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) fbi->var.activate = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) fbi->fbops = ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) fbi->flags = FBINFO_FLAG_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412) fbi->pseudo_palette = mx3fbi->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) mutex_init(&mx3fbi->mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) /* Allocate colormap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) ret = fb_alloc_cmap(&fbi->cmap, 16, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) framebuffer_release(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) return fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) struct device *dev = mx3fb->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) struct mx3fb_platform_data *mx3fb_pdata = dev_get_platdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) const char *name = mx3fb_pdata->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) unsigned int irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) struct fb_info *fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433) struct mx3fb_info *mx3fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) const struct fb_videomode *mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) int ret, num_modes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) if (mx3fb_pdata->disp_data_fmt >= ARRAY_SIZE(di_mappings)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) dev_err(dev, "Illegal display data format %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) mx3fb_pdata->disp_data_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) ichan->client = mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444) irq = ichan->eof_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) if (ichan->dma_chan.chan_id != IDMAC_SDC_0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) fbi = mx3fb_init_fbinfo(dev, &mx3fb_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) if (!fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) if (!fb_mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) fb_mode = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) if (!fb_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) goto emode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461) if (mx3fb_pdata->mode && mx3fb_pdata->num_modes) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) mode = mx3fb_pdata->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) num_modes = mx3fb_pdata->num_modes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) mode = mx3fb_modedb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) num_modes = ARRAY_SIZE(mx3fb_modedb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) if (!fb_find_mode(&fbi->var, fbi, fb_mode, mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) num_modes, NULL, default_bpp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) goto emode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) fb_videomode_to_modelist(mode, num_modes, &fbi->modelist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) /* Default Y virtual size is 2x panel size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) fbi->var.yres_virtual = fbi->var.yres * 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) mx3fb->fbi = fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) /* set Display Interface clock period */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) mx3fb_write_reg(mx3fb, 0x00100010L, DI_HSP_CLK_PER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) /* Might need to trigger HSP clock change - see 44.3.3.8.5 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) sdc_set_brightness(mx3fb, 255);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) sdc_set_global_alpha(mx3fb, true, 0xFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) sdc_set_color_key(mx3fb, IDMAC_SDC_0, false, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) mx3fbi = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) mx3fbi->idmac_channel = ichan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) mx3fbi->ipu_ch = ichan->dma_chan.chan_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) mx3fbi->mx3fb = mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) mx3fbi->blank = FB_BLANK_NORMAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) mx3fb->disp_data_fmt = mx3fb_pdata->disp_data_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) init_completion(&mx3fbi->flip_cmpl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499) disable_irq(ichan->eof_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) dev_dbg(mx3fb->dev, "disabling irq %d\n", ichan->eof_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) ret = __set_par(fbi, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) goto esetpar;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) __blank(FB_BLANK_UNBLANK, fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507) dev_info(dev, "registered, using mode %s\n", fb_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) ret = register_framebuffer(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) goto erfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) erfb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) esetpar:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) emode:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) fb_dealloc_cmap(&fbi->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) framebuffer_release(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) static bool chan_filter(struct dma_chan *chan, void *arg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) struct dma_chan_request *rq = arg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) struct mx3fb_platform_data *mx3fb_pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) if (!imx_dma_is_ipu(chan))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) if (!rq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) dev = rq->mx3fb->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) mx3fb_pdata = dev_get_platdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) return rq->id == chan->chan_id &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540) mx3fb_pdata->dma_dev == chan->device->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543) static void release_fbi(struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) mx3fb_unmap_video_memory(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) fb_dealloc_cmap(&fbi->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) unregister_framebuffer(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) framebuffer_release(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) static int mx3fb_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) struct resource *sdc_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) struct mx3fb_data *mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) dma_cap_mask_t mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) struct dma_chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561) struct dma_chan_request rq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564) * Display Interface (DI) and Synchronous Display Controller (SDC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) * registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) sdc_reg = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) if (!sdc_reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) mx3fb = devm_kzalloc(&pdev->dev, sizeof(*mx3fb), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) if (!mx3fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) spin_lock_init(&mx3fb->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577) mx3fb->reg_base = ioremap(sdc_reg->start, resource_size(sdc_reg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) if (!mx3fb->reg_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) goto eremap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) pr_debug("Remapped %pR at %p\n", sdc_reg, mx3fb->reg_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) /* IDMAC interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) dmaengine_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) mx3fb->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) platform_set_drvdata(pdev, mx3fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) rq.mx3fb = mx3fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) dma_cap_zero(mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) dma_cap_set(DMA_SLAVE, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) dma_cap_set(DMA_PRIVATE, mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) rq.id = IDMAC_SDC_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) chan = dma_request_channel(mask, chan_filter, &rq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598) if (!chan) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) goto ersdc0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) mx3fb->backlight_level = 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) ret = init_fb_chan(mx3fb, to_idmac_chan(chan));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) goto eisdc0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) mx3fb_init_backlight(mx3fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613) eisdc0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) dma_release_channel(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) ersdc0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) dmaengine_put();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617) iounmap(mx3fb->reg_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) eremap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) dev_err(dev, "mx3fb: failed to register fb\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) static int mx3fb_remove(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) struct mx3fb_data *mx3fb = platform_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) struct fb_info *fbi = mx3fb->fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) struct mx3fb_info *mx3_fbi = fbi->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) struct dma_chan *chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) chan = &mx3_fbi->idmac_channel->dma_chan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) release_fbi(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633) mx3fb_exit_backlight(mx3fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) dma_release_channel(chan);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) dmaengine_put();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) iounmap(mx3fb->reg_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) static struct platform_driver mx3fb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) .name = MX3FB_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646) .probe = mx3fb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) .remove = mx3fb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) .suspend = mx3fb_suspend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) .resume = mx3fb_resume,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653) * Parse user specified options (`video=mx3fb:')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) * example:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) * video=mx3fb:bpp=16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) static int __init mx3fb_setup(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) #ifndef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) char *opt, *options = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) if (fb_get_options("mx3fb", &options))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) while ((opt = strsep(&options, ",")) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) if (!*opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671) if (!strncmp(opt, "bpp=", 4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) default_bpp = simple_strtoul(opt + 4, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) fb_mode = opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) static int __init mx3fb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) int ret = mx3fb_setup();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688) ret = platform_driver_register(&mx3fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692) static void __exit mx3fb_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) platform_driver_unregister(&mx3fb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) module_init(mx3fb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) module_exit(mx3fb_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) MODULE_AUTHOR("Freescale Semiconductor, Inc.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) MODULE_DESCRIPTION("MX3 framebuffer driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) MODULE_ALIAS("platform:" MX3FB_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703) MODULE_LICENSE("GPL v2");