diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2013-08-29 09:40:14 -0400 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2013-08-29 09:40:14 -0400 |
commit | 53bd1a4283798dfa392442cf28b6ee94b54e3284 (patch) | |
tree | 37a315a75881127dcc0737986173f33e2d352baa /drivers/video | |
parent | fd3cd7ee126b2c3768d5253e12ac51868b0652f1 (diff) | |
parent | 979778ffdbb5686c78f9045947e5f870c496fd0f (diff) |
Merge branch '3.12/da8xx' into 3.12/fbdev
Merge da8xx-fb improvements from Darren Etheridge.
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/Kconfig | 8 | ||||
-rw-r--r-- | drivers/video/da8xx-fb.c | 352 |
2 files changed, 211 insertions, 149 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index a421fd432bfc..b49f5b55f708 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -2221,15 +2221,17 @@ config FB_SH7760 | |||
2221 | panels <= 320 pixel horizontal resolution. | 2221 | panels <= 320 pixel horizontal resolution. |
2222 | 2222 | ||
2223 | config FB_DA8XX | 2223 | config FB_DA8XX |
2224 | tristate "DA8xx/OMAP-L1xx Framebuffer support" | 2224 | tristate "DA8xx/OMAP-L1xx/AM335x Framebuffer support" |
2225 | depends on FB && ARCH_DAVINCI_DA8XX | 2225 | depends on FB && (ARCH_DAVINCI_DA8XX || SOC_AM33XX) |
2226 | select FB_CFB_FILLRECT | 2226 | select FB_CFB_FILLRECT |
2227 | select FB_CFB_COPYAREA | 2227 | select FB_CFB_COPYAREA |
2228 | select FB_CFB_IMAGEBLIT | 2228 | select FB_CFB_IMAGEBLIT |
2229 | select FB_CFB_REV_PIXELS_IN_BYTE | 2229 | select FB_CFB_REV_PIXELS_IN_BYTE |
2230 | select FB_MODE_HELPERS | ||
2231 | select VIDEOMODE_HELPERS | ||
2230 | ---help--- | 2232 | ---help--- |
2231 | This is the frame buffer device driver for the TI LCD controller | 2233 | This is the frame buffer device driver for the TI LCD controller |
2232 | found on DA8xx/OMAP-L1xx SoCs. | 2234 | found on DA8xx/OMAP-L1xx/AM335x SoCs. |
2233 | If unsure, say N. | 2235 | If unsure, say N. |
2234 | 2236 | ||
2235 | config FB_VIRTUAL | 2237 | config FB_VIRTUAL |
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 0810939936f4..ea9771f98301 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c | |||
@@ -131,29 +131,28 @@ | |||
131 | 131 | ||
132 | #define WSI_TIMEOUT 50 | 132 | #define WSI_TIMEOUT 50 |
133 | #define PALETTE_SIZE 256 | 133 | #define PALETTE_SIZE 256 |
134 | #define LEFT_MARGIN 64 | 134 | |
135 | #define RIGHT_MARGIN 64 | 135 | #define CLK_MIN_DIV 2 |
136 | #define UPPER_MARGIN 32 | 136 | #define CLK_MAX_DIV 255 |
137 | #define LOWER_MARGIN 32 | ||
138 | 137 | ||
139 | static void __iomem *da8xx_fb_reg_base; | 138 | static void __iomem *da8xx_fb_reg_base; |
140 | static struct resource *lcdc_regs; | ||
141 | static unsigned int lcd_revision; | 139 | static unsigned int lcd_revision; |
142 | static irq_handler_t lcdc_irq_handler; | 140 | static irq_handler_t lcdc_irq_handler; |
143 | static wait_queue_head_t frame_done_wq; | 141 | static wait_queue_head_t frame_done_wq; |
144 | static int frame_done_flag; | 142 | static int frame_done_flag; |
145 | 143 | ||
146 | static inline unsigned int lcdc_read(unsigned int addr) | 144 | static unsigned int lcdc_read(unsigned int addr) |
147 | { | 145 | { |
148 | return (unsigned int)__raw_readl(da8xx_fb_reg_base + (addr)); | 146 | return (unsigned int)__raw_readl(da8xx_fb_reg_base + (addr)); |
149 | } | 147 | } |
150 | 148 | ||
151 | static inline void lcdc_write(unsigned int val, unsigned int addr) | 149 | static void lcdc_write(unsigned int val, unsigned int addr) |
152 | { | 150 | { |
153 | __raw_writel(val, da8xx_fb_reg_base + (addr)); | 151 | __raw_writel(val, da8xx_fb_reg_base + (addr)); |
154 | } | 152 | } |
155 | 153 | ||
156 | struct da8xx_fb_par { | 154 | struct da8xx_fb_par { |
155 | struct device *dev; | ||
157 | resource_size_t p_palette_base; | 156 | resource_size_t p_palette_base; |
158 | unsigned char *v_palette_base; | 157 | unsigned char *v_palette_base; |
159 | dma_addr_t vram_phys; | 158 | dma_addr_t vram_phys; |
@@ -164,7 +163,6 @@ struct da8xx_fb_par { | |||
164 | struct clk *lcdc_clk; | 163 | struct clk *lcdc_clk; |
165 | int irq; | 164 | int irq; |
166 | unsigned int palette_sz; | 165 | unsigned int palette_sz; |
167 | unsigned int pxl_clk; | ||
168 | int blank; | 166 | int blank; |
169 | wait_queue_head_t vsync_wait; | 167 | wait_queue_head_t vsync_wait; |
170 | int vsync_flag; | 168 | int vsync_flag; |
@@ -178,29 +176,15 @@ struct da8xx_fb_par { | |||
178 | unsigned int which_dma_channel_done; | 176 | unsigned int which_dma_channel_done; |
179 | #ifdef CONFIG_CPU_FREQ | 177 | #ifdef CONFIG_CPU_FREQ |
180 | struct notifier_block freq_transition; | 178 | struct notifier_block freq_transition; |
181 | unsigned int lcd_fck_rate; | ||
182 | #endif | 179 | #endif |
180 | unsigned int lcdc_clk_rate; | ||
183 | void (*panel_power_ctrl)(int); | 181 | void (*panel_power_ctrl)(int); |
184 | u32 pseudo_palette[16]; | 182 | u32 pseudo_palette[16]; |
183 | struct fb_videomode mode; | ||
184 | struct lcd_ctrl_config cfg; | ||
185 | }; | 185 | }; |
186 | 186 | ||
187 | /* Variable Screen Information */ | 187 | static struct fb_var_screeninfo da8xx_fb_var; |
188 | static struct fb_var_screeninfo da8xx_fb_var = { | ||
189 | .xoffset = 0, | ||
190 | .yoffset = 0, | ||
191 | .transp = {0, 0, 0}, | ||
192 | .nonstd = 0, | ||
193 | .activate = 0, | ||
194 | .height = -1, | ||
195 | .width = -1, | ||
196 | .accel_flags = 0, | ||
197 | .left_margin = LEFT_MARGIN, | ||
198 | .right_margin = RIGHT_MARGIN, | ||
199 | .upper_margin = UPPER_MARGIN, | ||
200 | .lower_margin = LOWER_MARGIN, | ||
201 | .sync = 0, | ||
202 | .vmode = FB_VMODE_NONINTERLACED | ||
203 | }; | ||
204 | 188 | ||
205 | static struct fb_fix_screeninfo da8xx_fb_fix = { | 189 | static struct fb_fix_screeninfo da8xx_fb_fix = { |
206 | .id = "DA8xx FB Drv", | 190 | .id = "DA8xx FB Drv", |
@@ -219,7 +203,7 @@ static struct fb_videomode known_lcd_panels[] = { | |||
219 | .name = "Sharp_LCD035Q3DG01", | 203 | .name = "Sharp_LCD035Q3DG01", |
220 | .xres = 320, | 204 | .xres = 320, |
221 | .yres = 240, | 205 | .yres = 240, |
222 | .pixclock = 4608000, | 206 | .pixclock = KHZ2PICOS(4607), |
223 | .left_margin = 6, | 207 | .left_margin = 6, |
224 | .right_margin = 8, | 208 | .right_margin = 8, |
225 | .upper_margin = 2, | 209 | .upper_margin = 2, |
@@ -234,7 +218,7 @@ static struct fb_videomode known_lcd_panels[] = { | |||
234 | .name = "Sharp_LK043T1DG01", | 218 | .name = "Sharp_LK043T1DG01", |
235 | .xres = 480, | 219 | .xres = 480, |
236 | .yres = 272, | 220 | .yres = 272, |
237 | .pixclock = 7833600, | 221 | .pixclock = KHZ2PICOS(7833), |
238 | .left_margin = 2, | 222 | .left_margin = 2, |
239 | .right_margin = 2, | 223 | .right_margin = 2, |
240 | .upper_margin = 2, | 224 | .upper_margin = 2, |
@@ -249,7 +233,7 @@ static struct fb_videomode known_lcd_panels[] = { | |||
249 | .name = "SP10Q010", | 233 | .name = "SP10Q010", |
250 | .xres = 320, | 234 | .xres = 320, |
251 | .yres = 240, | 235 | .yres = 240, |
252 | .pixclock = 7833600, | 236 | .pixclock = KHZ2PICOS(7833), |
253 | .left_margin = 10, | 237 | .left_margin = 10, |
254 | .right_margin = 10, | 238 | .right_margin = 10, |
255 | .upper_margin = 10, | 239 | .upper_margin = 10, |
@@ -261,8 +245,13 @@ static struct fb_videomode known_lcd_panels[] = { | |||
261 | }, | 245 | }, |
262 | }; | 246 | }; |
263 | 247 | ||
248 | static bool da8xx_fb_is_raster_enabled(void) | ||
249 | { | ||
250 | return !!(lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE); | ||
251 | } | ||
252 | |||
264 | /* Enable the Raster Engine of the LCD Controller */ | 253 | /* Enable the Raster Engine of the LCD Controller */ |
265 | static inline void lcd_enable_raster(void) | 254 | static void lcd_enable_raster(void) |
266 | { | 255 | { |
267 | u32 reg; | 256 | u32 reg; |
268 | 257 | ||
@@ -284,7 +273,7 @@ static inline void lcd_enable_raster(void) | |||
284 | } | 273 | } |
285 | 274 | ||
286 | /* Disable the Raster Engine of the LCD Controller */ | 275 | /* Disable the Raster Engine of the LCD Controller */ |
287 | static inline void lcd_disable_raster(bool wait_for_frame_done) | 276 | static void lcd_disable_raster(enum da8xx_frame_complete wait_for_frame_done) |
288 | { | 277 | { |
289 | u32 reg; | 278 | u32 reg; |
290 | int ret; | 279 | int ret; |
@@ -296,7 +285,8 @@ static inline void lcd_disable_raster(bool wait_for_frame_done) | |||
296 | /* return if already disabled */ | 285 | /* return if already disabled */ |
297 | return; | 286 | return; |
298 | 287 | ||
299 | if ((wait_for_frame_done == true) && (lcd_revision == LCD_VERSION_2)) { | 288 | if ((wait_for_frame_done == DA8XX_FRAME_WAIT) && |
289 | (lcd_revision == LCD_VERSION_2)) { | ||
300 | frame_done_flag = 0; | 290 | frame_done_flag = 0; |
301 | ret = wait_event_interruptible_timeout(frame_done_wq, | 291 | ret = wait_event_interruptible_timeout(frame_done_wq, |
302 | frame_done_flag != 0, | 292 | frame_done_flag != 0, |
@@ -331,7 +321,7 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par) | |||
331 | reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | | 321 | reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | |
332 | LCD_V2_END_OF_FRAME0_INT_ENA | | 322 | LCD_V2_END_OF_FRAME0_INT_ENA | |
333 | LCD_V2_END_OF_FRAME1_INT_ENA | | 323 | LCD_V2_END_OF_FRAME1_INT_ENA | |
334 | LCD_FRAME_DONE; | 324 | LCD_FRAME_DONE | LCD_SYNC_LOST; |
335 | lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); | 325 | lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); |
336 | } | 326 | } |
337 | reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; | 327 | reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; |
@@ -565,10 +555,11 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, | |||
565 | break; | 555 | break; |
566 | case 24: | 556 | case 24: |
567 | reg |= LCD_V2_TFT_24BPP_MODE; | 557 | reg |= LCD_V2_TFT_24BPP_MODE; |
558 | break; | ||
568 | case 32: | 559 | case 32: |
560 | reg |= LCD_V2_TFT_24BPP_MODE; | ||
569 | reg |= LCD_V2_TFT_24BPP_UNPACK; | 561 | reg |= LCD_V2_TFT_24BPP_UNPACK; |
570 | break; | 562 | break; |
571 | |||
572 | case 8: | 563 | case 8: |
573 | par->palette_sz = 256 * 2; | 564 | par->palette_sz = 256 * 2; |
574 | break; | 565 | break; |
@@ -681,11 +672,8 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
681 | } | 672 | } |
682 | #undef CNVT_TOHW | 673 | #undef CNVT_TOHW |
683 | 674 | ||
684 | static void lcd_reset(struct da8xx_fb_par *par) | 675 | static void da8xx_fb_lcd_reset(void) |
685 | { | 676 | { |
686 | /* Disable the Raster if previously Enabled */ | ||
687 | lcd_disable_raster(false); | ||
688 | |||
689 | /* DMA has to be disabled */ | 677 | /* DMA has to be disabled */ |
690 | lcdc_write(0, LCD_DMA_CTRL_REG); | 678 | lcdc_write(0, LCD_DMA_CTRL_REG); |
691 | lcdc_write(0, LCD_RASTER_CTRL_REG); | 679 | lcdc_write(0, LCD_RASTER_CTRL_REG); |
@@ -698,21 +686,76 @@ static void lcd_reset(struct da8xx_fb_par *par) | |||
698 | } | 686 | } |
699 | } | 687 | } |
700 | 688 | ||
701 | static void lcd_calc_clk_divider(struct da8xx_fb_par *par) | 689 | static int da8xx_fb_config_clk_divider(struct da8xx_fb_par *par, |
690 | unsigned lcdc_clk_div, | ||
691 | unsigned lcdc_clk_rate) | ||
702 | { | 692 | { |
703 | unsigned int lcd_clk, div; | 693 | int ret; |
704 | 694 | ||
705 | lcd_clk = clk_get_rate(par->lcdc_clk); | 695 | if (par->lcdc_clk_rate != lcdc_clk_rate) { |
706 | div = lcd_clk / par->pxl_clk; | 696 | ret = clk_set_rate(par->lcdc_clk, lcdc_clk_rate); |
697 | if (IS_ERR_VALUE(ret)) { | ||
698 | dev_err(par->dev, | ||
699 | "unable to set clock rate at %u\n", | ||
700 | lcdc_clk_rate); | ||
701 | return ret; | ||
702 | } | ||
703 | par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk); | ||
704 | } | ||
707 | 705 | ||
708 | /* Configure the LCD clock divisor. */ | 706 | /* Configure the LCD clock divisor. */ |
709 | lcdc_write(LCD_CLK_DIVISOR(div) | | 707 | lcdc_write(LCD_CLK_DIVISOR(lcdc_clk_div) | |
710 | (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); | 708 | (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); |
711 | 709 | ||
712 | if (lcd_revision == LCD_VERSION_2) | 710 | if (lcd_revision == LCD_VERSION_2) |
713 | lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN | | 711 | lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN | |
714 | LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG); | 712 | LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG); |
715 | 713 | ||
714 | return 0; | ||
715 | } | ||
716 | |||
717 | static unsigned int da8xx_fb_calc_clk_divider(struct da8xx_fb_par *par, | ||
718 | unsigned pixclock, | ||
719 | unsigned *lcdc_clk_rate) | ||
720 | { | ||
721 | unsigned lcdc_clk_div; | ||
722 | |||
723 | pixclock = PICOS2KHZ(pixclock) * 1000; | ||
724 | |||
725 | *lcdc_clk_rate = par->lcdc_clk_rate; | ||
726 | |||
727 | if (pixclock < (*lcdc_clk_rate / CLK_MAX_DIV)) { | ||
728 | *lcdc_clk_rate = clk_round_rate(par->lcdc_clk, | ||
729 | pixclock * CLK_MAX_DIV); | ||
730 | lcdc_clk_div = CLK_MAX_DIV; | ||
731 | } else if (pixclock > (*lcdc_clk_rate / CLK_MIN_DIV)) { | ||
732 | *lcdc_clk_rate = clk_round_rate(par->lcdc_clk, | ||
733 | pixclock * CLK_MIN_DIV); | ||
734 | lcdc_clk_div = CLK_MIN_DIV; | ||
735 | } else { | ||
736 | lcdc_clk_div = *lcdc_clk_rate / pixclock; | ||
737 | } | ||
738 | |||
739 | return lcdc_clk_div; | ||
740 | } | ||
741 | |||
742 | static int da8xx_fb_calc_config_clk_divider(struct da8xx_fb_par *par, | ||
743 | struct fb_videomode *mode) | ||
744 | { | ||
745 | unsigned lcdc_clk_rate; | ||
746 | unsigned lcdc_clk_div = da8xx_fb_calc_clk_divider(par, mode->pixclock, | ||
747 | &lcdc_clk_rate); | ||
748 | |||
749 | return da8xx_fb_config_clk_divider(par, lcdc_clk_div, lcdc_clk_rate); | ||
750 | } | ||
751 | |||
752 | static unsigned da8xx_fb_round_clk(struct da8xx_fb_par *par, | ||
753 | unsigned pixclock) | ||
754 | { | ||
755 | unsigned lcdc_clk_div, lcdc_clk_rate; | ||
756 | |||
757 | lcdc_clk_div = da8xx_fb_calc_clk_divider(par, pixclock, &lcdc_clk_rate); | ||
758 | return KHZ2PICOS(lcdc_clk_rate / (1000 * lcdc_clk_div)); | ||
716 | } | 759 | } |
717 | 760 | ||
718 | static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, | 761 | static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, |
@@ -721,10 +764,11 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, | |||
721 | u32 bpp; | 764 | u32 bpp; |
722 | int ret = 0; | 765 | int ret = 0; |
723 | 766 | ||
724 | lcd_reset(par); | 767 | ret = da8xx_fb_calc_config_clk_divider(par, panel); |
725 | 768 | if (IS_ERR_VALUE(ret)) { | |
726 | /* Calculate the divider */ | 769 | dev_err(par->dev, "unable to configure clock\n"); |
727 | lcd_calc_clk_divider(par); | 770 | return ret; |
771 | } | ||
728 | 772 | ||
729 | if (panel->sync & FB_SYNC_CLK_INVERT) | 773 | if (panel->sync & FB_SYNC_CLK_INVERT) |
730 | lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | | 774 | lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | |
@@ -773,7 +817,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) | |||
773 | u32 stat = lcdc_read(LCD_MASKED_STAT_REG); | 817 | u32 stat = lcdc_read(LCD_MASKED_STAT_REG); |
774 | 818 | ||
775 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { | 819 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { |
776 | lcd_disable_raster(false); | 820 | lcd_disable_raster(DA8XX_FRAME_NOWAIT); |
777 | lcdc_write(stat, LCD_MASKED_STAT_REG); | 821 | lcdc_write(stat, LCD_MASKED_STAT_REG); |
778 | lcd_enable_raster(); | 822 | lcd_enable_raster(); |
779 | } else if (stat & LCD_PL_LOAD_DONE) { | 823 | } else if (stat & LCD_PL_LOAD_DONE) { |
@@ -783,7 +827,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) | |||
783 | * interrupt via the following write to the status register. If | 827 | * interrupt via the following write to the status register. If |
784 | * this is done after then one gets multiple PL done interrupts. | 828 | * this is done after then one gets multiple PL done interrupts. |
785 | */ | 829 | */ |
786 | lcd_disable_raster(false); | 830 | lcd_disable_raster(DA8XX_FRAME_NOWAIT); |
787 | 831 | ||
788 | lcdc_write(stat, LCD_MASKED_STAT_REG); | 832 | lcdc_write(stat, LCD_MASKED_STAT_REG); |
789 | 833 | ||
@@ -836,7 +880,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg) | |||
836 | u32 reg_ras; | 880 | u32 reg_ras; |
837 | 881 | ||
838 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { | 882 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { |
839 | lcd_disable_raster(false); | 883 | lcd_disable_raster(DA8XX_FRAME_NOWAIT); |
840 | lcdc_write(stat, LCD_STAT_REG); | 884 | lcdc_write(stat, LCD_STAT_REG); |
841 | lcd_enable_raster(); | 885 | lcd_enable_raster(); |
842 | } else if (stat & LCD_PL_LOAD_DONE) { | 886 | } else if (stat & LCD_PL_LOAD_DONE) { |
@@ -846,7 +890,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg) | |||
846 | * interrupt via the following write to the status register. If | 890 | * interrupt via the following write to the status register. If |
847 | * this is done after then one gets multiple PL done interrupts. | 891 | * this is done after then one gets multiple PL done interrupts. |
848 | */ | 892 | */ |
849 | lcd_disable_raster(false); | 893 | lcd_disable_raster(DA8XX_FRAME_NOWAIT); |
850 | 894 | ||
851 | lcdc_write(stat, LCD_STAT_REG); | 895 | lcdc_write(stat, LCD_STAT_REG); |
852 | 896 | ||
@@ -888,6 +932,9 @@ static int fb_check_var(struct fb_var_screeninfo *var, | |||
888 | struct fb_info *info) | 932 | struct fb_info *info) |
889 | { | 933 | { |
890 | int err = 0; | 934 | int err = 0; |
935 | struct da8xx_fb_par *par = info->par; | ||
936 | int bpp = var->bits_per_pixel >> 3; | ||
937 | unsigned long line_size = var->xres_virtual * bpp; | ||
891 | 938 | ||
892 | if (var->bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1) | 939 | if (var->bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1) |
893 | return -EINVAL; | 940 | return -EINVAL; |
@@ -955,6 +1002,23 @@ static int fb_check_var(struct fb_var_screeninfo *var, | |||
955 | var->green.msb_right = 0; | 1002 | var->green.msb_right = 0; |
956 | var->blue.msb_right = 0; | 1003 | var->blue.msb_right = 0; |
957 | var->transp.msb_right = 0; | 1004 | var->transp.msb_right = 0; |
1005 | |||
1006 | if (line_size * var->yres_virtual > par->vram_size) | ||
1007 | var->yres_virtual = par->vram_size / line_size; | ||
1008 | |||
1009 | if (var->yres > var->yres_virtual) | ||
1010 | var->yres = var->yres_virtual; | ||
1011 | |||
1012 | if (var->xres > var->xres_virtual) | ||
1013 | var->xres = var->xres_virtual; | ||
1014 | |||
1015 | if (var->xres + var->xoffset > var->xres_virtual) | ||
1016 | var->xoffset = var->xres_virtual - var->xres; | ||
1017 | if (var->yres + var->yoffset > var->yres_virtual) | ||
1018 | var->yoffset = var->yres_virtual - var->yres; | ||
1019 | |||
1020 | var->pixclock = da8xx_fb_round_clk(par, var->pixclock); | ||
1021 | |||
958 | return err; | 1022 | return err; |
959 | } | 1023 | } |
960 | 1024 | ||
@@ -966,10 +1030,10 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb, | |||
966 | 1030 | ||
967 | par = container_of(nb, struct da8xx_fb_par, freq_transition); | 1031 | par = container_of(nb, struct da8xx_fb_par, freq_transition); |
968 | if (val == CPUFREQ_POSTCHANGE) { | 1032 | if (val == CPUFREQ_POSTCHANGE) { |
969 | if (par->lcd_fck_rate != clk_get_rate(par->lcdc_clk)) { | 1033 | if (par->lcdc_clk_rate != clk_get_rate(par->lcdc_clk)) { |
970 | par->lcd_fck_rate = clk_get_rate(par->lcdc_clk); | 1034 | par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk); |
971 | lcd_disable_raster(true); | 1035 | lcd_disable_raster(DA8XX_FRAME_WAIT); |
972 | lcd_calc_clk_divider(par); | 1036 | da8xx_fb_calc_config_clk_divider(par, &par->mode); |
973 | if (par->blank == FB_BLANK_UNBLANK) | 1037 | if (par->blank == FB_BLANK_UNBLANK) |
974 | lcd_enable_raster(); | 1038 | lcd_enable_raster(); |
975 | } | 1039 | } |
@@ -978,7 +1042,7 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb, | |||
978 | return 0; | 1042 | return 0; |
979 | } | 1043 | } |
980 | 1044 | ||
981 | static inline int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par) | 1045 | static int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par) |
982 | { | 1046 | { |
983 | par->freq_transition.notifier_call = lcd_da8xx_cpufreq_transition; | 1047 | par->freq_transition.notifier_call = lcd_da8xx_cpufreq_transition; |
984 | 1048 | ||
@@ -986,7 +1050,7 @@ static inline int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par) | |||
986 | CPUFREQ_TRANSITION_NOTIFIER); | 1050 | CPUFREQ_TRANSITION_NOTIFIER); |
987 | } | 1051 | } |
988 | 1052 | ||
989 | static inline void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par) | 1053 | static void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par) |
990 | { | 1054 | { |
991 | cpufreq_unregister_notifier(&par->freq_transition, | 1055 | cpufreq_unregister_notifier(&par->freq_transition, |
992 | CPUFREQ_TRANSITION_NOTIFIER); | 1056 | CPUFREQ_TRANSITION_NOTIFIER); |
@@ -1006,7 +1070,7 @@ static int fb_remove(struct platform_device *dev) | |||
1006 | if (par->panel_power_ctrl) | 1070 | if (par->panel_power_ctrl) |
1007 | par->panel_power_ctrl(0); | 1071 | par->panel_power_ctrl(0); |
1008 | 1072 | ||
1009 | lcd_disable_raster(true); | 1073 | lcd_disable_raster(DA8XX_FRAME_WAIT); |
1010 | lcdc_write(0, LCD_RASTER_CTRL_REG); | 1074 | lcdc_write(0, LCD_RASTER_CTRL_REG); |
1011 | 1075 | ||
1012 | /* disable DMA */ | 1076 | /* disable DMA */ |
@@ -1018,12 +1082,9 @@ static int fb_remove(struct platform_device *dev) | |||
1018 | par->p_palette_base); | 1082 | par->p_palette_base); |
1019 | dma_free_coherent(NULL, par->vram_size, par->vram_virt, | 1083 | dma_free_coherent(NULL, par->vram_size, par->vram_virt, |
1020 | par->vram_phys); | 1084 | par->vram_phys); |
1021 | free_irq(par->irq, par); | ||
1022 | pm_runtime_put_sync(&dev->dev); | 1085 | pm_runtime_put_sync(&dev->dev); |
1023 | pm_runtime_disable(&dev->dev); | 1086 | pm_runtime_disable(&dev->dev); |
1024 | framebuffer_release(info); | 1087 | framebuffer_release(info); |
1025 | iounmap(da8xx_fb_reg_base); | ||
1026 | release_mem_region(lcdc_regs->start, resource_size(lcdc_regs)); | ||
1027 | 1088 | ||
1028 | } | 1089 | } |
1029 | return 0; | 1090 | return 0; |
@@ -1122,7 +1183,7 @@ static int cfb_blank(int blank, struct fb_info *info) | |||
1122 | if (par->panel_power_ctrl) | 1183 | if (par->panel_power_ctrl) |
1123 | par->panel_power_ctrl(0); | 1184 | par->panel_power_ctrl(0); |
1124 | 1185 | ||
1125 | lcd_disable_raster(true); | 1186 | lcd_disable_raster(DA8XX_FRAME_WAIT); |
1126 | break; | 1187 | break; |
1127 | default: | 1188 | default: |
1128 | ret = -EINVAL; | 1189 | ret = -EINVAL; |
@@ -1183,9 +1244,50 @@ static int da8xx_pan_display(struct fb_var_screeninfo *var, | |||
1183 | return ret; | 1244 | return ret; |
1184 | } | 1245 | } |
1185 | 1246 | ||
1247 | static int da8xxfb_set_par(struct fb_info *info) | ||
1248 | { | ||
1249 | struct da8xx_fb_par *par = info->par; | ||
1250 | int ret; | ||
1251 | bool raster = da8xx_fb_is_raster_enabled(); | ||
1252 | |||
1253 | if (raster) | ||
1254 | lcd_disable_raster(DA8XX_FRAME_WAIT); | ||
1255 | |||
1256 | fb_var_to_videomode(&par->mode, &info->var); | ||
1257 | |||
1258 | par->cfg.bpp = info->var.bits_per_pixel; | ||
1259 | |||
1260 | info->fix.visual = (par->cfg.bpp <= 8) ? | ||
1261 | FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; | ||
1262 | info->fix.line_length = (par->mode.xres * par->cfg.bpp) / 8; | ||
1263 | |||
1264 | ret = lcd_init(par, &par->cfg, &par->mode); | ||
1265 | if (ret < 0) { | ||
1266 | dev_err(par->dev, "lcd init failed\n"); | ||
1267 | return ret; | ||
1268 | } | ||
1269 | |||
1270 | par->dma_start = info->fix.smem_start + | ||
1271 | info->var.yoffset * info->fix.line_length + | ||
1272 | info->var.xoffset * info->var.bits_per_pixel / 8; | ||
1273 | par->dma_end = par->dma_start + | ||
1274 | info->var.yres * info->fix.line_length - 1; | ||
1275 | |||
1276 | lcdc_write(par->dma_start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
1277 | lcdc_write(par->dma_end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
1278 | lcdc_write(par->dma_start, LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
1279 | lcdc_write(par->dma_end, LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
1280 | |||
1281 | if (raster) | ||
1282 | lcd_enable_raster(); | ||
1283 | |||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1186 | static struct fb_ops da8xx_fb_ops = { | 1287 | static struct fb_ops da8xx_fb_ops = { |
1187 | .owner = THIS_MODULE, | 1288 | .owner = THIS_MODULE, |
1188 | .fb_check_var = fb_check_var, | 1289 | .fb_check_var = fb_check_var, |
1290 | .fb_set_par = da8xxfb_set_par, | ||
1189 | .fb_setcolreg = fb_setcolreg, | 1291 | .fb_setcolreg = fb_setcolreg, |
1190 | .fb_pan_display = da8xx_pan_display, | 1292 | .fb_pan_display = da8xx_pan_display, |
1191 | .fb_ioctl = fb_ioctl, | 1293 | .fb_ioctl = fb_ioctl, |
@@ -1195,33 +1297,38 @@ static struct fb_ops da8xx_fb_ops = { | |||
1195 | .fb_blank = cfb_blank, | 1297 | .fb_blank = cfb_blank, |
1196 | }; | 1298 | }; |
1197 | 1299 | ||
1198 | /* Calculate and return pixel clock period in pico seconds */ | 1300 | static struct fb_videomode *da8xx_fb_get_videomode(struct platform_device *dev) |
1199 | static unsigned int da8xxfb_pixel_clk_period(struct da8xx_fb_par *par) | ||
1200 | { | 1301 | { |
1201 | unsigned int lcd_clk, div; | 1302 | struct da8xx_lcdc_platform_data *fb_pdata = dev->dev.platform_data; |
1202 | unsigned int configured_pix_clk; | 1303 | struct fb_videomode *lcdc_info; |
1203 | unsigned long long pix_clk_period_picosec = 1000000000000ULL; | 1304 | int i; |
1204 | 1305 | ||
1205 | lcd_clk = clk_get_rate(par->lcdc_clk); | 1306 | for (i = 0, lcdc_info = known_lcd_panels; |
1206 | div = lcd_clk / par->pxl_clk; | 1307 | i < ARRAY_SIZE(known_lcd_panels); i++, lcdc_info++) { |
1207 | configured_pix_clk = (lcd_clk / div); | 1308 | if (strcmp(fb_pdata->type, lcdc_info->name) == 0) |
1309 | break; | ||
1310 | } | ||
1208 | 1311 | ||
1209 | do_div(pix_clk_period_picosec, configured_pix_clk); | 1312 | if (i == ARRAY_SIZE(known_lcd_panels)) { |
1313 | dev_err(&dev->dev, "no panel found\n"); | ||
1314 | return NULL; | ||
1315 | } | ||
1316 | dev_info(&dev->dev, "found %s panel\n", lcdc_info->name); | ||
1210 | 1317 | ||
1211 | return pix_clk_period_picosec; | 1318 | return lcdc_info; |
1212 | } | 1319 | } |
1213 | 1320 | ||
1214 | static int fb_probe(struct platform_device *device) | 1321 | static int fb_probe(struct platform_device *device) |
1215 | { | 1322 | { |
1216 | struct da8xx_lcdc_platform_data *fb_pdata = | 1323 | struct da8xx_lcdc_platform_data *fb_pdata = |
1217 | device->dev.platform_data; | 1324 | device->dev.platform_data; |
1325 | static struct resource *lcdc_regs; | ||
1218 | struct lcd_ctrl_config *lcd_cfg; | 1326 | struct lcd_ctrl_config *lcd_cfg; |
1219 | struct fb_videomode *lcdc_info; | 1327 | struct fb_videomode *lcdc_info; |
1220 | struct fb_info *da8xx_fb_info; | 1328 | struct fb_info *da8xx_fb_info; |
1221 | struct clk *fb_clk = NULL; | ||
1222 | struct da8xx_fb_par *par; | 1329 | struct da8xx_fb_par *par; |
1223 | resource_size_t len; | 1330 | struct clk *tmp_lcdc_clk; |
1224 | int ret, i; | 1331 | int ret; |
1225 | unsigned long ulcm; | 1332 | unsigned long ulcm; |
1226 | 1333 | ||
1227 | if (fb_pdata == NULL) { | 1334 | if (fb_pdata == NULL) { |
@@ -1229,30 +1336,19 @@ static int fb_probe(struct platform_device *device) | |||
1229 | return -ENOENT; | 1336 | return -ENOENT; |
1230 | } | 1337 | } |
1231 | 1338 | ||
1232 | lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0); | 1339 | lcdc_info = da8xx_fb_get_videomode(device); |
1233 | if (!lcdc_regs) { | 1340 | if (lcdc_info == NULL) |
1234 | dev_err(&device->dev, | 1341 | return -ENODEV; |
1235 | "Can not get memory resource for LCD controller\n"); | ||
1236 | return -ENOENT; | ||
1237 | } | ||
1238 | |||
1239 | len = resource_size(lcdc_regs); | ||
1240 | 1342 | ||
1241 | lcdc_regs = request_mem_region(lcdc_regs->start, len, lcdc_regs->name); | 1343 | lcdc_regs = platform_get_resource(device, IORESOURCE_MEM, 0); |
1242 | if (!lcdc_regs) | 1344 | da8xx_fb_reg_base = devm_ioremap_resource(&device->dev, lcdc_regs); |
1243 | return -EBUSY; | 1345 | if (IS_ERR(da8xx_fb_reg_base)) |
1244 | 1346 | return PTR_ERR(da8xx_fb_reg_base); | |
1245 | da8xx_fb_reg_base = ioremap(lcdc_regs->start, len); | ||
1246 | if (!da8xx_fb_reg_base) { | ||
1247 | ret = -EBUSY; | ||
1248 | goto err_request_mem; | ||
1249 | } | ||
1250 | 1347 | ||
1251 | fb_clk = clk_get(&device->dev, "fck"); | 1348 | tmp_lcdc_clk = devm_clk_get(&device->dev, "fck"); |
1252 | if (IS_ERR(fb_clk)) { | 1349 | if (IS_ERR(tmp_lcdc_clk)) { |
1253 | dev_err(&device->dev, "Can not get device clock\n"); | 1350 | dev_err(&device->dev, "Can not get device clock\n"); |
1254 | ret = -ENODEV; | 1351 | return PTR_ERR(tmp_lcdc_clk); |
1255 | goto err_ioremap; | ||
1256 | } | 1352 | } |
1257 | 1353 | ||
1258 | pm_runtime_enable(&device->dev); | 1354 | pm_runtime_enable(&device->dev); |
@@ -1275,22 +1371,12 @@ static int fb_probe(struct platform_device *device) | |||
1275 | break; | 1371 | break; |
1276 | } | 1372 | } |
1277 | 1373 | ||
1278 | for (i = 0, lcdc_info = known_lcd_panels; | 1374 | lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data; |
1279 | i < ARRAY_SIZE(known_lcd_panels); | ||
1280 | i++, lcdc_info++) { | ||
1281 | if (strcmp(fb_pdata->type, lcdc_info->name) == 0) | ||
1282 | break; | ||
1283 | } | ||
1284 | 1375 | ||
1285 | if (i == ARRAY_SIZE(known_lcd_panels)) { | 1376 | if (!lcd_cfg) { |
1286 | dev_err(&device->dev, "GLCD: No valid panel found\n"); | 1377 | ret = -EINVAL; |
1287 | ret = -ENODEV; | ||
1288 | goto err_pm_runtime_disable; | 1378 | goto err_pm_runtime_disable; |
1289 | } else | 1379 | } |
1290 | dev_info(&device->dev, "GLCD: Found %s panel\n", | ||
1291 | fb_pdata->type); | ||
1292 | |||
1293 | lcd_cfg = (struct lcd_ctrl_config *)fb_pdata->controller_data; | ||
1294 | 1380 | ||
1295 | da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par), | 1381 | da8xx_fb_info = framebuffer_alloc(sizeof(struct da8xx_fb_par), |
1296 | &device->dev); | 1382 | &device->dev); |
@@ -1301,21 +1387,18 @@ static int fb_probe(struct platform_device *device) | |||
1301 | } | 1387 | } |
1302 | 1388 | ||
1303 | par = da8xx_fb_info->par; | 1389 | par = da8xx_fb_info->par; |
1304 | par->lcdc_clk = fb_clk; | 1390 | par->dev = &device->dev; |
1305 | #ifdef CONFIG_CPU_FREQ | 1391 | par->lcdc_clk = tmp_lcdc_clk; |
1306 | par->lcd_fck_rate = clk_get_rate(fb_clk); | 1392 | par->lcdc_clk_rate = clk_get_rate(par->lcdc_clk); |
1307 | #endif | ||
1308 | par->pxl_clk = lcdc_info->pixclock; | ||
1309 | if (fb_pdata->panel_power_ctrl) { | 1393 | if (fb_pdata->panel_power_ctrl) { |
1310 | par->panel_power_ctrl = fb_pdata->panel_power_ctrl; | 1394 | par->panel_power_ctrl = fb_pdata->panel_power_ctrl; |
1311 | par->panel_power_ctrl(1); | 1395 | par->panel_power_ctrl(1); |
1312 | } | 1396 | } |
1313 | 1397 | ||
1314 | if (lcd_init(par, lcd_cfg, lcdc_info) < 0) { | 1398 | fb_videomode_to_var(&da8xx_fb_var, lcdc_info); |
1315 | dev_err(&device->dev, "lcd_init failed\n"); | 1399 | par->cfg = *lcd_cfg; |
1316 | ret = -EFAULT; | 1400 | |
1317 | goto err_release_fb; | 1401 | da8xx_fb_lcd_reset(); |
1318 | } | ||
1319 | 1402 | ||
1320 | /* allocate frame buffer */ | 1403 | /* allocate frame buffer */ |
1321 | par->vram_size = lcdc_info->xres * lcdc_info->yres * lcd_cfg->bpp; | 1404 | par->vram_size = lcdc_info->xres * lcdc_info->yres * lcd_cfg->bpp; |
@@ -1363,27 +1446,10 @@ static int fb_probe(struct platform_device *device) | |||
1363 | goto err_release_pl_mem; | 1446 | goto err_release_pl_mem; |
1364 | } | 1447 | } |
1365 | 1448 | ||
1366 | /* Initialize par */ | ||
1367 | da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp; | ||
1368 | |||
1369 | da8xx_fb_var.xres = lcdc_info->xres; | ||
1370 | da8xx_fb_var.xres_virtual = lcdc_info->xres; | ||
1371 | |||
1372 | da8xx_fb_var.yres = lcdc_info->yres; | ||
1373 | da8xx_fb_var.yres_virtual = lcdc_info->yres * LCD_NUM_BUFFERS; | ||
1374 | |||
1375 | da8xx_fb_var.grayscale = | 1449 | da8xx_fb_var.grayscale = |
1376 | lcd_cfg->panel_shade == MONOCHROME ? 1 : 0; | 1450 | lcd_cfg->panel_shade == MONOCHROME ? 1 : 0; |
1377 | da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp; | 1451 | da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp; |
1378 | 1452 | ||
1379 | da8xx_fb_var.hsync_len = lcdc_info->hsync_len; | ||
1380 | da8xx_fb_var.vsync_len = lcdc_info->vsync_len; | ||
1381 | da8xx_fb_var.right_margin = lcdc_info->right_margin; | ||
1382 | da8xx_fb_var.left_margin = lcdc_info->left_margin; | ||
1383 | da8xx_fb_var.lower_margin = lcdc_info->lower_margin; | ||
1384 | da8xx_fb_var.upper_margin = lcdc_info->upper_margin; | ||
1385 | da8xx_fb_var.pixclock = da8xxfb_pixel_clk_period(par); | ||
1386 | |||
1387 | /* Initialize fbinfo */ | 1453 | /* Initialize fbinfo */ |
1388 | da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT; | 1454 | da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT; |
1389 | da8xx_fb_info->fix = da8xx_fb_fix; | 1455 | da8xx_fb_info->fix = da8xx_fb_fix; |
@@ -1433,8 +1499,8 @@ static int fb_probe(struct platform_device *device) | |||
1433 | lcdc_irq_handler = lcdc_irq_handler_rev02; | 1499 | lcdc_irq_handler = lcdc_irq_handler_rev02; |
1434 | } | 1500 | } |
1435 | 1501 | ||
1436 | ret = request_irq(par->irq, lcdc_irq_handler, 0, | 1502 | ret = devm_request_irq(&device->dev, par->irq, lcdc_irq_handler, 0, |
1437 | DRIVER_NAME, par); | 1503 | DRIVER_NAME, par); |
1438 | if (ret) | 1504 | if (ret) |
1439 | goto irq_freq; | 1505 | goto irq_freq; |
1440 | return 0; | 1506 | return 0; |
@@ -1463,12 +1529,6 @@ err_pm_runtime_disable: | |||
1463 | pm_runtime_put_sync(&device->dev); | 1529 | pm_runtime_put_sync(&device->dev); |
1464 | pm_runtime_disable(&device->dev); | 1530 | pm_runtime_disable(&device->dev); |
1465 | 1531 | ||
1466 | err_ioremap: | ||
1467 | iounmap(da8xx_fb_reg_base); | ||
1468 | |||
1469 | err_request_mem: | ||
1470 | release_mem_region(lcdc_regs->start, len); | ||
1471 | |||
1472 | return ret; | 1532 | return ret; |
1473 | } | 1533 | } |
1474 | 1534 | ||
@@ -1546,7 +1606,7 @@ static int fb_suspend(struct platform_device *dev, pm_message_t state) | |||
1546 | par->panel_power_ctrl(0); | 1606 | par->panel_power_ctrl(0); |
1547 | 1607 | ||
1548 | fb_set_suspend(info, 1); | 1608 | fb_set_suspend(info, 1); |
1549 | lcd_disable_raster(true); | 1609 | lcd_disable_raster(DA8XX_FRAME_WAIT); |
1550 | lcd_context_save(); | 1610 | lcd_context_save(); |
1551 | pm_runtime_put_sync(&dev->dev); | 1611 | pm_runtime_put_sync(&dev->dev); |
1552 | console_unlock(); | 1612 | console_unlock(); |