1/* Copyright (c) 2008-2009, Code Aurora Forum. All rights reserved. 2 * 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License version 2 and 5 * only version 2 as published by the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 15 * 02110-1301, USA. 16 */ 17 18#include <linux/module.h> 19#include <linux/kernel.h> 20#include <linux/slab.h> 21#include <linux/delay.h> 22#include <linux/mm.h> 23#include <linux/fb.h> 24#include <linux/init.h> 25#include <linux/ioport.h> 26#include <linux/device.h> 27#include <linux/dma-mapping.h> 28 29#include "msm_fb.h" 30#include "mddihost.h" 31#include "mddihosti.h" 32 33#include <linux/clk.h> 34#include <mach/clk.h> 35 36struct semaphore mddi_host_mutex; 37 38struct clk *mddi_io_clk; 39static boolean mddi_host_powered = FALSE; 40static boolean mddi_host_initialized = FALSE; 41extern uint32 *mddi_reg_read_value_ptr; 42 43mddi_lcd_func_type mddi_lcd; 44 45extern mddi_client_capability_type mddi_client_capability_pkt; 46 47#ifdef FEATURE_MDDI_HITACHI 48extern void mddi_hitachi_window_adjust(uint16 x1, 49 uint16 x2, uint16 y1, uint16 y2); 50#endif 51 52extern void mddi_toshiba_lcd_init(void); 53 54#ifdef FEATURE_MDDI_S6D0142 55extern void mddi_s6d0142_lcd_init(void); 56extern void mddi_s6d0142_window_adjust(uint16 x1, 57 uint16 x2, 58 uint16 y1, 59 uint16 y2, 60 mddi_llist_done_cb_type done_cb); 61#endif 62 63void mddi_init(void) 64{ 65 if (mddi_host_initialized) 66 return; 67 68 mddi_host_initialized = TRUE; 69 70 init_MUTEX(&mddi_host_mutex); 71 72 if (!mddi_host_powered) { 73 down(&mddi_host_mutex); 74 mddi_host_init(MDDI_HOST_PRIM); 75 mddi_host_powered = TRUE; 76 up(&mddi_host_mutex); 77 mdelay(10); 78 } 79} 80 81int mddi_host_register_read(uint32 reg_addr, 82 uint32 *reg_value_ptr, boolean wait, mddi_host_type host) { 83 mddi_linked_list_type *curr_llist_ptr; 84 mddi_register_access_packet_type *regacc_pkt_ptr; 85 uint16 curr_llist_idx; 86 int ret = 0; 87 88 if (in_interrupt()) 89 MDDI_MSG_CRIT("Called from ISR context\n"); 90 91 if (!mddi_host_powered) { 92 MDDI_MSG_ERR("MDDI powered down!\n"); 93 mddi_init(); 94 } 95 96 down(&mddi_host_mutex); 97 98 mddi_reg_read_value_ptr = reg_value_ptr; 99 curr_llist_idx = mddi_get_reg_read_llist_item(host, TRUE); 100 if (curr_llist_idx == UNASSIGNED_INDEX) { 101 up(&mddi_host_mutex); 102 103 /* need to change this to some sort of wait */ 104 MDDI_MSG_ERR("Attempting to queue up more than 1 reg read\n"); 105 return -EINVAL; 106 } 107 108 curr_llist_ptr = &llist_extern[host][curr_llist_idx]; 109 curr_llist_ptr->link_controller_flags = 0x11; 110 curr_llist_ptr->packet_header_count = 14; 111 curr_llist_ptr->packet_data_count = 0; 112 113 curr_llist_ptr->next_packet_pointer = NULL; 114 curr_llist_ptr->packet_data_pointer = NULL; 115 curr_llist_ptr->reserved = 0; 116 117 regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; 118 119 regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count; 120 regacc_pkt_ptr->packet_type = 146; /* register access packet */ 121 regacc_pkt_ptr->bClient_ID = 0; 122 regacc_pkt_ptr->read_write_info = 0x8001; 123 regacc_pkt_ptr->register_address = reg_addr; 124 125 /* now adjust pointers */ 126 mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait, 127 NULL, host); 128 /* need to check if we can write the pointer or not */ 129 130 up(&mddi_host_mutex); 131 132 if (wait) { 133 int wait_ret; 134 135 mddi_linked_list_notify_type *llist_notify_ptr; 136 llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx]; 137 wait_ret = wait_for_completion_timeout( 138 &(llist_notify_ptr->done_comp), 5 * HZ); 139 140 if (wait_ret <= 0) 141 ret = -EBUSY; 142 143 if (wait_ret < 0) 144 printk(KERN_ERR "%s: failed to wait for completion!\n", 145 __func__); 146 else if (!wait_ret) 147 printk(KERN_ERR "%s: Timed out waiting!\n", __func__); 148 } 149 150 MDDI_MSG_DEBUG("Reg Read value=0x%x\n", *reg_value_ptr); 151 152 return ret; 153} /* mddi_host_register_read */ 154 155int mddi_host_register_write(uint32 reg_addr, 156 uint32 reg_val, enum mddi_data_packet_size_type packet_size, 157 boolean wait, mddi_llist_done_cb_type done_cb, mddi_host_type host) { 158 mddi_linked_list_type *curr_llist_ptr; 159 mddi_linked_list_type *curr_llist_dma_ptr; 160 mddi_register_access_packet_type *regacc_pkt_ptr; 161 uint16 curr_llist_idx; 162 int ret = 0; 163 164 if (in_interrupt()) 165 MDDI_MSG_CRIT("Called from ISR context\n"); 166 167 if (!mddi_host_powered) { 168 MDDI_MSG_ERR("MDDI powered down!\n"); 169 mddi_init(); 170 } 171 172 down(&mddi_host_mutex); 173 174 curr_llist_idx = mddi_get_next_free_llist_item(host, TRUE); 175 curr_llist_ptr = &llist_extern[host][curr_llist_idx]; 176 curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx]; 177 178 curr_llist_ptr->link_controller_flags = 1; 179 curr_llist_ptr->packet_header_count = 14; 180 curr_llist_ptr->packet_data_count = 4; 181 182 curr_llist_ptr->next_packet_pointer = NULL; 183 curr_llist_ptr->reserved = 0; 184 185 regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; 186 187 regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + 188 (uint16)packet_size; 189 regacc_pkt_ptr->packet_type = 146; /* register access packet */ 190 regacc_pkt_ptr->bClient_ID = 0; 191 regacc_pkt_ptr->read_write_info = 0x0001; 192 regacc_pkt_ptr->register_address = reg_addr; 193 regacc_pkt_ptr->register_data_list = reg_val; 194 195 MDDI_MSG_DEBUG("Reg Access write reg=0x%x, value=0x%x\n", 196 regacc_pkt_ptr->register_address, 197 regacc_pkt_ptr->register_data_list); 198 199 regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt; 200 curr_llist_ptr->packet_data_pointer = 201 (void *)(®acc_pkt_ptr->register_data_list); 202 203 /* now adjust pointers */ 204 mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, wait, 205 done_cb, host); 206 207 up(&mddi_host_mutex); 208 209 if (wait) { 210 int wait_ret; 211 212 mddi_linked_list_notify_type *llist_notify_ptr; 213 llist_notify_ptr = &llist_extern_notify[host][curr_llist_idx]; 214 wait_ret = wait_for_completion_timeout( 215 &(llist_notify_ptr->done_comp), 5 * HZ); 216 217 if (wait_ret <= 0) 218 ret = -EBUSY; 219 220 if (wait_ret < 0) 221 printk(KERN_ERR "%s: failed to wait for completion!\n", 222 __func__); 223 else if (!wait_ret) 224 printk(KERN_ERR "%s: Timed out waiting!\n", __func__); 225 } 226 227 return ret; 228} /* mddi_host_register_write */ 229 230boolean mddi_host_register_read_int 231 (uint32 reg_addr, uint32 *reg_value_ptr, mddi_host_type host) { 232 mddi_linked_list_type *curr_llist_ptr; 233 mddi_register_access_packet_type *regacc_pkt_ptr; 234 uint16 curr_llist_idx; 235 236 if (!in_interrupt()) 237 MDDI_MSG_CRIT("Called from TASK context\n"); 238 239 if (!mddi_host_powered) { 240 MDDI_MSG_ERR("MDDI powered down!\n"); 241 return FALSE; 242 } 243 244 if (down_trylock(&mddi_host_mutex) != 0) 245 return FALSE; 246 247 mddi_reg_read_value_ptr = reg_value_ptr; 248 curr_llist_idx = mddi_get_reg_read_llist_item(host, FALSE); 249 if (curr_llist_idx == UNASSIGNED_INDEX) { 250 up(&mddi_host_mutex); 251 return FALSE; 252 } 253 254 curr_llist_ptr = &llist_extern[host][curr_llist_idx]; 255 curr_llist_ptr->link_controller_flags = 0x11; 256 curr_llist_ptr->packet_header_count = 14; 257 curr_llist_ptr->packet_data_count = 0; 258 259 curr_llist_ptr->next_packet_pointer = NULL; 260 curr_llist_ptr->packet_data_pointer = NULL; 261 curr_llist_ptr->reserved = 0; 262 263 regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; 264 265 regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count; 266 regacc_pkt_ptr->packet_type = 146; /* register access packet */ 267 regacc_pkt_ptr->bClient_ID = 0; 268 regacc_pkt_ptr->read_write_info = 0x8001; 269 regacc_pkt_ptr->register_address = reg_addr; 270 271 /* now adjust pointers */ 272 mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE, 273 NULL, host); 274 /* need to check if we can write the pointer or not */ 275 276 up(&mddi_host_mutex); 277 278 return TRUE; 279 280} /* mddi_host_register_read */ 281 282boolean mddi_host_register_write_int 283 (uint32 reg_addr, 284 uint32 reg_val, mddi_llist_done_cb_type done_cb, mddi_host_type host) { 285 mddi_linked_list_type *curr_llist_ptr; 286 mddi_linked_list_type *curr_llist_dma_ptr; 287 mddi_register_access_packet_type *regacc_pkt_ptr; 288 uint16 curr_llist_idx; 289 290 if (!in_interrupt()) 291 MDDI_MSG_CRIT("Called from TASK context\n"); 292 293 if (!mddi_host_powered) { 294 MDDI_MSG_ERR("MDDI powered down!\n"); 295 return FALSE; 296 } 297 298 if (down_trylock(&mddi_host_mutex) != 0) 299 return FALSE; 300 301 curr_llist_idx = mddi_get_next_free_llist_item(host, FALSE); 302 if (curr_llist_idx == UNASSIGNED_INDEX) { 303 up(&mddi_host_mutex); 304 return FALSE; 305 } 306 307 curr_llist_ptr = &llist_extern[host][curr_llist_idx]; 308 curr_llist_dma_ptr = &llist_dma_extern[host][curr_llist_idx]; 309 310 curr_llist_ptr->link_controller_flags = 1; 311 curr_llist_ptr->packet_header_count = 14; 312 curr_llist_ptr->packet_data_count = 4; 313 314 curr_llist_ptr->next_packet_pointer = NULL; 315 curr_llist_ptr->reserved = 0; 316 317 regacc_pkt_ptr = &curr_llist_ptr->packet_header.register_pkt; 318 319 regacc_pkt_ptr->packet_length = curr_llist_ptr->packet_header_count + 4; 320 regacc_pkt_ptr->packet_type = 146; /* register access packet */ 321 regacc_pkt_ptr->bClient_ID = 0; 322 regacc_pkt_ptr->read_write_info = 0x0001; 323 regacc_pkt_ptr->register_address = reg_addr; 324 regacc_pkt_ptr->register_data_list = reg_val; 325 326 regacc_pkt_ptr = &curr_llist_dma_ptr->packet_header.register_pkt; 327 curr_llist_ptr->packet_data_pointer = 328 (void *)(&(regacc_pkt_ptr->register_data_list)); 329 330 /* now adjust pointers */ 331 mddi_queue_forward_packets(curr_llist_idx, curr_llist_idx, FALSE, 332 done_cb, host); 333 up(&mddi_host_mutex); 334 335 return TRUE; 336 337} /* mddi_host_register_write */ 338 339void mddi_wait(uint16 time_ms) 340{ 341 mdelay(time_ms); 342} 343 344void mddi_client_lcd_vsync_detected(boolean detected) 345{ 346 if (mddi_lcd.vsync_detected) 347 (*mddi_lcd.vsync_detected) (detected); 348} 349 350/* extended version of function includes done callback */ 351void mddi_window_adjust_ext(struct msm_fb_data_type *mfd, 352 uint16 x1, 353 uint16 x2, 354 uint16 y1, 355 uint16 y2, mddi_llist_done_cb_type done_cb) 356{ 357#ifdef FEATURE_MDDI_HITACHI 358 if (mfd->panel.id == HITACHI) 359 mddi_hitachi_window_adjust(x1, x2, y1, y2); 360#elif defined(FEATURE_MDDI_S6D0142) 361 if (mfd->panel.id == MDDI_LCD_S6D0142) 362 mddi_s6d0142_window_adjust(x1, x2, y1, y2, done_cb); 363#else 364 /* Do nothing then... except avoid lint/compiler warnings */ 365 (void)x1; 366 (void)x2; 367 (void)y1; 368 (void)y2; 369 (void)done_cb; 370#endif 371} 372 373void mddi_window_adjust(struct msm_fb_data_type *mfd, 374 uint16 x1, uint16 x2, uint16 y1, uint16 y2) 375{ 376 mddi_window_adjust_ext(mfd, x1, x2, y1, y2, NULL); 377} 378