/drivers/char/sun4i_g2d/g2d.c
C | 320 lines | 246 code | 45 blank | 29 comment | 41 complexity | 86e1032edbc3c1d43388aad177b6bb99 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
1/* 2 * drivers/char/sun4i_g2d/g2d.c 3 * 4 * (C) Copyright 2007-2012 5 * Allwinner Technology Co., Ltd. <www.allwinnertech.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20 * MA 02111-1307 USA 21 */ 22 23#include "g2d.h" 24#include <linux/clk.h> 25#include <linux/interrupt.h> 26#include <mach/clock.h> 27#include "g2d_driver_i.h" 28 29struct clk *g2d_ahbclk,*g2d_dramclk,*g2d_mclk,*g2d_src; 30extern __g2d_drv_t g2d_ext_hd; 31 32int g2d_openclk(void) 33{ 34 __u32 ret; 35 36 /* ahb g2d gating */ 37 g2d_ahbclk = clk_get(NULL,"ahb_de_mix"); 38 39 /* sdram g2d gating */ 40 g2d_dramclk = clk_get(NULL,"sdram_de_mix"); 41 42 /* g2d gating */ 43 g2d_mclk = clk_get(NULL,"de_mix"); 44 45 /*disable mp clk reset*/ 46 clk_reset(g2d_mclk,0); 47 48 /* set g2d clk value */ 49 g2d_src = clk_get(NULL,"sdram_pll_p");//video_pll0 50 ret = clk_set_parent(g2d_mclk, g2d_src); 51 clk_put(g2d_src); 52 53 ret = clk_get_rate(g2d_src); 54 clk_set_rate(g2d_mclk,ret/2); 55 56 return 0; 57} 58 59int g2d_closeclk(void)/* used once when g2d driver exit */ 60{ 61 clk_disable(g2d_ahbclk); 62 clk_disable(g2d_dramclk); 63 clk_disable(g2d_mclk); 64 65 clk_put(g2d_ahbclk); 66 clk_put(g2d_dramclk); 67 clk_put(g2d_mclk); 68 69 return 0; 70} 71 72int g2d_clk_on(void)/* used in request */ 73{ 74 clk_enable(g2d_ahbclk); 75 clk_enable(g2d_dramclk); 76 clk_enable(g2d_mclk); 77 78 return 0; 79} 80 81int g2d_clk_off(void)/* used in release */ 82{ 83 clk_disable(g2d_ahbclk); 84 clk_disable(g2d_dramclk); 85 clk_disable(g2d_mclk); 86 87 return 0; 88} 89 90irqreturn_t g2d_handle_irq(int irq, void *dev_id) 91{ 92 __u32 irq_flag; 93 94 irq_flag = mixer_get_irq(); 95 if(irq_flag & G2D_FINISH_IRQ) 96 { 97 mixer_clear_init(); 98 g2d_ext_hd.finish_flag = 1; 99 wake_up(&g2d_ext_hd.queue); 100 } 101 102 return IRQ_HANDLED; 103} 104 105int g2d_init(g2d_init_para *para) 106{ 107 mixer_set_reg_base(para->g2d_base); 108 109 return 0; 110} 111 112int g2d_exit(void) 113{ 114 __u8 err = 0; 115 g2d_closeclk(); 116 117 return err; 118} 119 120int g2d_wait_cmd_finish(void) 121{ 122 long timeout = 50; /* 30ms */ 123 124 timeout = wait_event_timeout(g2d_ext_hd.queue, g2d_ext_hd.finish_flag == 1, msecs_to_jiffies(timeout)); 125 if(timeout == 0) 126 { 127 mixer_clear_init(); 128 printk("wait g2d irq pending flag timeout\n"); 129 g2d_ext_hd.finish_flag = 1; 130 wake_up(&g2d_ext_hd.queue); 131 return -1; 132 } 133 return 0; 134} 135 136int g2d_blit(g2d_blt * para) 137{ 138 __s32 err = 0; 139 140 /* check the parameter valid */ 141 if(((para->src_rect.x < 0)&&((-para->src_rect.x) > para->src_rect.w)) || 142 ((para->src_rect.y < 0)&&((-para->src_rect.y) > para->src_rect.h)) || 143 ((para->dst_x < 0)&&((-para->dst_x) > para->src_rect.w)) || 144 ((para->dst_y < 0)&&((-para->dst_y) > para->src_rect.h)) || 145 ((para->src_rect.x > 0)&&(para->src_rect.x > para->src_image.w - 1)) || 146 ((para->src_rect.y > 0)&&(para->src_rect.y > para->src_image.h - 1)) || 147 ((para->dst_x > 0)&&(para->dst_x > para->dst_image.w - 1)) || 148 ((para->dst_y > 0)&&(para->dst_y > para->dst_image.h - 1))) 149 { 150 printk("invalid blit parameter setting"); 151 return -EINVAL; 152 } 153 else 154 { 155 if(((para->src_rect.x < 0)&&((-para->src_rect.x) < para->src_rect.w))) 156 { 157 para->src_rect.w = para->src_rect.w + para->src_rect.x; 158 para->src_rect.x = 0; 159 } 160 else if((para->src_rect.x + para->src_rect.w) > para->src_image.w) 161 { 162 para->src_rect.w = para->src_image.w - para->src_rect.x; 163 } 164 if(((para->src_rect.y < 0)&&((-para->src_rect.y) < para->src_rect.h))) 165 { 166 para->src_rect.h = para->src_rect.h + para->src_rect.y; 167 para->src_rect.y = 0; 168 } 169 else if((para->src_rect.y + para->src_rect.h) > para->src_image.h) 170 { 171 para->src_rect.h = para->src_image.h - para->src_rect.y; 172 } 173 174 if(((para->dst_x < 0)&&((-para->dst_x) < para->src_rect.w))) 175 { 176 para->src_rect.w = para->src_rect.w + para->dst_x; 177 para->src_rect.x = (-para->dst_x); 178 para->dst_x = 0; 179 } 180 else if((para->dst_x + para->src_rect.w) > para->dst_image.w) 181 { 182 para->src_rect.w = para->dst_image.w - para->dst_x; 183 } 184 if(((para->dst_y < 0)&&((-para->dst_y) < para->src_rect.h))) 185 { 186 para->src_rect.h = para->src_rect.h + para->dst_y; 187 para->src_rect.y = (-para->dst_y); 188 para->dst_y = 0; 189 } 190 else if((para->dst_y + para->src_rect.h) > para->dst_image.h) 191 { 192 para->src_rect.h = para->dst_image.h - para->dst_y; 193 } 194 } 195 196 g2d_ext_hd.finish_flag = 0; 197 err = mixer_blt(para); 198 199 return err; 200} 201 202int g2d_fill(g2d_fillrect * para) 203{ 204 __s32 err = 0; 205 206 /* check the parameter valid */ 207 if(((para->dst_rect.x < 0)&&((-para->dst_rect.x)>para->dst_rect.w)) || 208 ((para->dst_rect.y < 0)&&((-para->dst_rect.y)>para->dst_rect.h)) || 209 ((para->dst_rect.x > 0)&&(para->dst_rect.x > para->dst_image.w - 1)) || 210 ((para->dst_rect.y > 0)&&(para->dst_rect.y > para->dst_image.h - 1))) 211 { 212 printk("invalid fillrect parameter setting"); 213 return -EINVAL; 214 } 215 else 216 { 217 if(((para->dst_rect.x < 0)&&((-para->dst_rect.x) < para->dst_rect.w))) 218 { 219 para->dst_rect.w = para->dst_rect.w + para->dst_rect.x; 220 para->dst_rect.x = 0; 221 } 222 else if((para->dst_rect.x + para->dst_rect.w) > para->dst_image.w) 223 { 224 para->dst_rect.w = para->dst_image.w - para->dst_rect.x; 225 } 226 if(((para->dst_rect.y < 0)&&((-para->dst_rect.y) < para->dst_rect.h))) 227 { 228 para->dst_rect.h = para->dst_rect.h + para->dst_rect.y; 229 para->dst_rect.y = 0; 230 } 231 else if((para->dst_rect.y + para->dst_rect.h) > para->dst_image.h) 232 { 233 para->dst_rect.h = para->dst_image.h - para->dst_rect.y; 234 } 235 } 236 237 g2d_ext_hd.finish_flag = 0; 238 err = mixer_fillrectangle(para); 239 240 return err; 241} 242 243int g2d_stretchblit(g2d_stretchblt * para) 244{ 245 __s32 err = 0; 246 247 /* check the parameter valid */ 248 if(((para->src_rect.x < 0)&&((-para->src_rect.x) > para->src_rect.w)) || 249 ((para->src_rect.y < 0)&&((-para->src_rect.y) > para->src_rect.h)) || 250 ((para->dst_rect.x < 0)&&((-para->dst_rect.x) > para->dst_rect.w)) || 251 ((para->dst_rect.y < 0)&&((-para->dst_rect.y) > para->dst_rect.h)) || 252 ((para->src_rect.x > 0)&&(para->src_rect.x > para->src_image.w - 1)) || 253 ((para->src_rect.y > 0)&&(para->src_rect.y > para->src_image.h - 1)) || 254 ((para->dst_rect.x > 0)&&(para->dst_rect.x > para->dst_image.w - 1)) || 255 ((para->dst_rect.y > 0)&&(para->dst_rect.y > para->dst_image.h - 1))) 256 { 257 printk("invalid stretchblit parameter setting"); 258 return -EINVAL; 259 } 260 else 261 { 262 if(((para->src_rect.x < 0)&&((-para->src_rect.x) < para->src_rect.w))) 263 { 264 para->src_rect.w = para->src_rect.w + para->src_rect.x; 265 para->src_rect.x = 0; 266 } 267 else if((para->src_rect.x + para->src_rect.w) > para->src_image.w) 268 { 269 para->src_rect.w = para->src_image.w - para->src_rect.x; 270 } 271 if(((para->src_rect.y < 0)&&((-para->src_rect.y) < para->src_rect.h))) 272 { 273 para->src_rect.h = para->src_rect.h + para->src_rect.y; 274 para->src_rect.y = 0; 275 } 276 else if((para->src_rect.y + para->src_rect.h) > para->src_image.h) 277 { 278 para->src_rect.h = para->src_image.h - para->src_rect.y; 279 } 280 281 if(((para->dst_rect.x < 0)&&((-para->dst_rect.x) < para->dst_rect.w))) 282 { 283 para->dst_rect.w = para->dst_rect.w + para->dst_rect.x; 284 para->dst_rect.x = 0; 285 } 286 else if((para->dst_rect.x + para->dst_rect.w) > para->dst_image.w) 287 { 288 para->dst_rect.w = para->dst_image.w - para->dst_rect.x; 289 } 290 if(((para->dst_rect.y < 0)&&((-para->dst_rect.y) < para->dst_rect.h))) 291 { 292 para->dst_rect.h = para->dst_rect.h + para->dst_rect.y; 293 para->dst_rect.y = 0; 294 } 295 else if((para->dst_rect.y + para->dst_rect.h) > para->dst_image.h) 296 { 297 para->dst_rect.h = para->dst_image.h - para->dst_rect.y; 298 } 299 } 300 301 g2d_ext_hd.finish_flag = 0; 302 err = mixer_stretchblt(para); 303 304 return err; 305} 306 307int g2d_set_palette_table(g2d_palette *para) 308{ 309 310 if((para->pbuffer == NULL) || (para->size < 0) || (para->size>1024)) 311 { 312 printk("para invalid in mixer_set_palette\n"); 313 return -1; 314 } 315 316 mixer_set_palette(para); 317 318 return 0; 319} 320