1 /*
2  * LCD, LED and Button interface for Cobalt
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file "COPYING" in the main directory of this archive
6  * for more details.
7  *
8  * Copyright (C) 1996, 1997 by Andrew Bose
9  *
10  * Linux kernel version history:
11  *       March 2001: Ported from 2.0.34  by Liam Davies
12  *
13  */
14 
15 #define RTC_IO_EXTENT	0x10    /*Only really two ports, but...	*/
16 
17 #include <linux/config.h>
18 #include <linux/types.h>
19 #include <linux/errno.h>
20 #include <linux/miscdevice.h>
21 #include <linux/slab.h>
22 #include <linux/ioport.h>
23 #include <linux/fcntl.h>
24 #include <linux/mc146818rtc.h>
25 #include <linux/netdevice.h>
26 #include <linux/sched.h>
27 
28 #include <asm/io.h>
29 #include <asm/uaccess.h>
30 #include <asm/system.h>
31 #include <linux/delay.h>
32 
33 #include "lcd.h"
34 
35 static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
36                      unsigned long arg);
37 
38 static int lcd_present = 1;
39 
40 int led_state = 0;
41 
42 #if defined(CONFIG_TULIP) && 0
43 
44 #define MAX_INTERFACES	8
45 static linkcheck_func_t linkcheck_callbacks[MAX_INTERFACES];
46 static void *linkcheck_cookies[MAX_INTERFACES];
47 
lcd_register_linkcheck_func(int iface_num,void * func,void * cookie)48 int lcd_register_linkcheck_func(int iface_num, void *func, void *cookie)
49 {
50 	if (iface_num < 0 ||
51 	    iface_num >= MAX_INTERFACES ||
52 	    linkcheck_callbacks[iface_num] != NULL)
53 		return -1;
54 	linkcheck_callbacks[iface_num] = (linkcheck_func_t) func;
55 	linkcheck_cookies[iface_num] = cookie;
56 	return 0;
57 }
58 #endif
59 
lcd_ioctl(struct inode * inode,struct file * file,unsigned int cmd,unsigned long arg)60 static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
61 			unsigned long arg)
62 {
63 	struct lcd_display button_display;
64 	unsigned long address, a;
65 	int index;
66 
67 	switch (cmd) {
68 	case LCD_On:
69 		udelay(150);
70 		BusyCheck();
71 		LCDWriteInst(0x0F);
72 		break;
73 
74 	case LCD_Off:
75 		udelay(150);
76 		BusyCheck();
77 		LCDWriteInst(0x08);
78 		break;
79 
80 	case LCD_Reset:
81 		udelay(150);
82 		LCDWriteInst(0x3F);
83 		udelay(150);
84 		LCDWriteInst(0x3F);
85 		udelay(150);
86 		LCDWriteInst(0x3F);
87 		udelay(150);
88 		LCDWriteInst(0x3F);
89 		udelay(150);
90 		LCDWriteInst(0x01);
91 		udelay(150);
92 		LCDWriteInst(0x06);
93 		break;
94 
95 	case LCD_Clear:
96 		udelay(150);
97 		BusyCheck();
98        		LCDWriteInst(0x01);
99 		break;
100 
101 	case LCD_Cursor_Left:
102 		udelay(150);
103 		BusyCheck();
104 		LCDWriteInst(0x10);
105 		break;
106 
107 	case LCD_Cursor_Right:
108 		udelay(150);
109 		BusyCheck();
110 		LCDWriteInst(0x14);
111 		break;
112 
113 	case LCD_Cursor_Off:
114 		udelay(150);
115                 BusyCheck();
116                 LCDWriteInst(0x0C);
117 	        break;
118 
119         case LCD_Cursor_On:
120                 udelay(150);
121                 BusyCheck();
122                 LCDWriteInst(0x0F);
123                 break;
124 
125         case LCD_Blink_Off:
126                 udelay(150);
127                 BusyCheck();
128                 LCDWriteInst(0x0E);
129                 break;
130 
131 	case LCD_Get_Cursor_Pos:{
132                 struct lcd_display display;
133 
134 		udelay(150);
135                 BusyCheck();
136 		display.cursor_address = ( LCDReadInst );
137 		display.cursor_address = ( display.cursor_address & 0x07F );
138 		if(copy_to_user((struct lcd_display*)arg, &display, sizeof(struct lcd_display)))
139 		  return -EFAULT;
140 
141 		break;
142 		}
143 
144 
145 	case LCD_Set_Cursor_Pos: {
146                 struct lcd_display display;
147 
148                 if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display)))
149 		  return -EFAULT;
150 
151 		a = (display.cursor_address | kLCD_Addr );
152 
153                 udelay(150);
154                 BusyCheck();
155                 LCDWriteInst( a );
156 
157                 break;
158 		}
159 
160 	case LCD_Get_Cursor: {
161                 struct lcd_display display;
162 
163                 udelay(150);
164                 BusyCheck();
165 		display.character = LCDReadData;
166 
167 		if(copy_to_user((struct lcd_display*)arg, &display, sizeof(struct lcd_display)))
168 		  return -EFAULT;
169                 udelay(150);
170                 BusyCheck();
171                 LCDWriteInst(0x10);
172 
173 		break;
174 		}
175 
176 	case LCD_Set_Cursor:{
177                 struct lcd_display display;
178 
179                 if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display)))
180 		  return -EFAULT;
181 
182                 udelay(150);
183 		BusyCheck();
184                 LCDWriteData( display.character );
185                 udelay(150);
186                 BusyCheck();
187                 LCDWriteInst(0x10);
188 
189                 break;
190                 }
191 
192 
193 	case LCD_Disp_Left:
194 		udelay(150);
195 		BusyCheck();
196 		LCDWriteInst(0x18);
197 		break;
198 
199 	case LCD_Disp_Right:
200 		udelay(150);
201 		BusyCheck();
202 		LCDWriteInst(0x1C);
203 		break;
204 
205 	case LCD_Home:
206 		udelay(150);
207 		BusyCheck();
208 		LCDWriteInst(0x02);
209 		break;
210 
211 	case LCD_Write: {
212 		struct lcd_display display;
213 
214 
215                 if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display)))
216 		  return -EFAULT;
217 
218 		udelay(150);
219                 BusyCheck();
220                 LCDWriteInst(0x80);
221 		udelay(150);
222 		BusyCheck();
223 
224 		for (index = 0; index < (display.size1); index++) {
225 			udelay(150);
226 			BusyCheck();
227 			LCDWriteData( display.line1[index]);
228 			BusyCheck();
229 		}
230 
231 		udelay(150);
232 		BusyCheck();
233 		LCDWriteInst(0xC0);
234 		udelay(150);
235 		BusyCheck();
236                 for (index = 0; index < (display.size2); index++) {
237                         udelay(150);
238                         BusyCheck();
239                         LCDWriteData( display.line2[index]);
240 		}
241 
242 		break;
243 	}
244 
245 	case LCD_Read: {
246         	struct lcd_display display;
247 
248 		BusyCheck();
249 		for (address = kDD_R00; address <= kDD_R01; address++) {
250 			a = (address | kLCD_Addr );
251 
252 			udelay(150);
253 			BusyCheck();
254 			LCDWriteInst( a );
255 			udelay(150);
256 			BusyCheck();
257 			display.line1[address] = LCDReadData;
258 		}
259 
260 		display.line1[ 0x27 ] = '\0';
261 
262 		for (address = kDD_R10; address <= kDD_R11; address++) {
263 			a = (address | kLCD_Addr );
264 
265 			udelay(150);
266 	 		BusyCheck();
267         		LCDWriteInst( a );
268 
269         		udelay(150);
270 	 		BusyCheck();
271         		display.line2[address - 0x40 ] = LCDReadData;
272 		 }
273 
274 		display.line2[ 0x27 ] = '\0';
275 
276 		if(copy_to_user((struct lcd_display*)arg, &display,
277 				sizeof(struct lcd_display)))
278 		  return -EFAULT;
279 		break;
280 	}
281 
282 //  set all GPIO leds to led_display.leds
283 
284 	case LED_Set: {
285 		struct lcd_display led_display;
286 
287 
288 	        if(copy_from_user(&led_display, (struct lcd_display*)arg,
289 				  sizeof(struct lcd_display)))
290 		  return -EFAULT;
291 
292 		led_state = led_display.leds;
293 		LEDSet(led_state);
294 
295         	break;
296 	}
297 
298 
299 //  set only bit led_display.leds
300 
301         case LED_Bit_Set: {
302                 int i;
303 		int bit=1;
304                 struct lcd_display led_display;
305 
306 
307                 if(copy_from_user(&led_display, (struct lcd_display*)arg,
308 				  sizeof(struct lcd_display)))
309 		  return -EFAULT;
310 
311 		for (i=0;i<(int)led_display.leds;i++)
312 			{
313 				bit = 2*bit;
314 			}
315 
316 		led_state = led_state | bit;
317                 LEDSet(led_state);
318                 break;
319         }
320 
321 //  clear only bit led_display.leds
322 
323         case LED_Bit_Clear: {
324                 int i;
325 		int bit=1;
326                 struct lcd_display led_display;
327 
328 
329                 if(copy_from_user(&led_display, (struct lcd_display*)arg,
330 				  sizeof(struct lcd_display)))
331 		  return -EFAULT;
332 
333                 for (i=0;i<(int)led_display.leds;i++)
334                         {
335                                 bit = 2*bit;
336                         }
337 
338 		led_state = led_state &  ~bit;
339                 LEDSet(led_state);
340                 break;
341         }
342 
343 
344 	case BUTTON_Read: {
345 		button_display.buttons = GPIRead;
346                 if(copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display)))
347 		  return -EFAULT;
348 		break;
349 	}
350 
351         case LINK_Check: {
352                 button_display.buttons = *((volatile unsigned long *) (0xB0100060) );
353                 if(copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display)))
354 		  return -EFAULT;
355                 break;
356         }
357 
358 	case LINK_Check_2: {
359 		int iface_num;
360 
361 		/* panel-utils should pass in the desired interface status is wanted for
362 		 * in "buttons" of the structure.  We will set this to non-zero if the
363 		 * link is in fact up for the requested interface.  --DaveM
364 		 */
365 		if(copy_from_user(&button_display, (struct lcd_display *)arg, sizeof(button_display)))
366 		  return -EFAULT;
367 		iface_num = button_display.buttons;
368 #if defined(CONFIG_TULIP) && 0
369 		if (iface_num >= 0 &&
370 		    iface_num < MAX_INTERFACES &&
371 		    linkcheck_callbacks[iface_num] != NULL) {
372 			button_display.buttons =
373 				linkcheck_callbacks[iface_num](linkcheck_cookies[iface_num]);
374 		} else
375 #endif
376 			button_display.buttons = 0;
377 
378                 if(__copy_to_user((struct lcd_display*)arg, &button_display, sizeof(struct lcd_display)))
379 		  return -EFAULT;
380                 break;
381 	}
382 
383 //  Erase the flash
384 
385 	case FLASH_Erase: {
386 
387 		int ctr=0;
388 
389 		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
390 
391 		    // Chip Erase Sequence
392 		WRITE_FLASH( kFlash_Addr1, kFlash_Data1 );
393 		WRITE_FLASH( kFlash_Addr2, kFlash_Data2 );
394 		WRITE_FLASH( kFlash_Addr1, kFlash_Erase3 );
395 		WRITE_FLASH( kFlash_Addr1, kFlash_Data1 );
396 		WRITE_FLASH( kFlash_Addr2, kFlash_Data2 );
397 		WRITE_FLASH( kFlash_Addr1, kFlash_Erase6 );
398 
399 		printk( "Erasing Flash.\n");
400 
401 		while ( (!dqpoll(0x00000000,0xFF)) && (!timeout(0x00000000)) ) {
402 		    ctr++;
403 		}
404 
405 		printk("\n");
406 		printk("\n");
407 		printk("\n");
408 
409 		if (READ_FLASH(0x07FFF0)==0xFF) { printk("Erase Successful\r\n"); }
410 		else if (timeout) { printk("Erase Timed Out\r\n"); }
411 
412 	break;
413 	}
414 
415 // burn the flash
416 
417 	case FLASH_Burn: {
418 
419 		volatile unsigned long burn_addr;
420 		unsigned long flags;
421 		int i;
422 		unsigned char *rom;
423 
424 
425                 struct lcd_display display;
426 
427 		if (!capable(CAP_SYS_ADMIN)) return -EPERM;
428 
429                 if(copy_from_user(&display, (struct lcd_display*)arg, sizeof(struct lcd_display)))
430 		  return -EFAULT;
431 		rom = (unsigned char *) kmalloc((128),GFP_ATOMIC);
432                 if ( rom == NULL ) {
433                        printk ("broken\n");
434                        return 1;
435                    }
436 
437 		printk("Churning and Burning -");
438 		save_flags(flags);
439 		for (i=0; i<FLASH_SIZE; i=i+128) {
440 
441 		        if(copy_from_user(rom, display.RomImage + i, 128)) {
442 			   kfree(rom);
443 			   return -EFAULT;
444 			}
445 			burn_addr = kFlashBase + i;
446 			cli();
447 			for ( index = 0; index < ( 128 ) ; index++ )
448 		  	  {
449 
450 				WRITE_FLASH( kFlash_Addr1, kFlash_Data1 );
451 		 	    	WRITE_FLASH( kFlash_Addr2, kFlash_Data2 );
452 		 	    	WRITE_FLASH( kFlash_Addr1, kFlash_Prog );
453 		 	    	*((volatile unsigned char *)burn_addr) = (volatile unsigned char) rom[index];
454 
455 		   	 	 while ( (!dqpoll(burn_addr,(volatile unsigned char) rom[index])) && (!timeout(burn_addr)) ) {
456 		  	   		}
457 		  	   	burn_addr++;
458 		  	  }
459 			restore_flags(flags);
460                 	if ( *((volatile unsigned char *)(burn_addr-1)) == (volatile unsigned char) rom[index-1]  ) {
461                		 } else if (timeout) {
462                 	    printk("Program timed out\r\n");
463                		 }
464 
465 
466 		}
467 		kfree(rom);
468 
469 	break;
470 	}
471 
472 //  read the flash all at once
473 
474 	case FLASH_Read: {
475 
476 		unsigned char *user_bytes;
477                 volatile unsigned long read_addr;
478                 int i;
479 
480 		user_bytes = &(((struct lcd_display *)arg)->RomImage[0]);
481 
482 		if(!access_ok(VERIFY_WRITE, user_bytes, FLASH_SIZE))
483                          return -EFAULT;
484 
485 		printk("Reading Flash");
486 		for (i=0; i<FLASH_SIZE; i++) {
487 			unsigned char tmp_byte;
488 			read_addr = kFlashBase + i;
489 			tmp_byte = *((volatile unsigned char *)read_addr);
490 			if(__put_user (tmp_byte, &user_bytes[i]))
491 			  return -EFAULT;
492 		}
493 
494 
495 	break;
496 	}
497 
498 
499 
500 
501 
502 	default:
503 		return 0;
504 	break;
505 
506 	}
507 
508 	return 0;
509 
510 }
511 
lcd_open(struct inode * inode,struct file * file)512 static int lcd_open(struct inode *inode, struct file *file)
513 {
514 	if (!lcd_present)
515 		return -ENXIO;
516 	else
517 		return 0;
518 }
519 
520 /* Only RESET or NEXT counts as button pressed */
521 
button_pressed(void)522 static inline int button_pressed(void)
523 {
524 	unsigned long buttons = GPIRead;
525 
526 	if ( (buttons == BUTTON_Next) || (buttons == BUTTON_Next_B) || (buttons == BUTTON_Reset_B) )
527 		return buttons;
528 	return 0;
529 }
530 
531 /* LED daemon sits on this and we wake him up once a key is pressed. */
532 
533 static int lcd_waiters = 0;
534 
lcd_read(struct inode * inode,struct file * file,char * buf,unsigned long count)535 static long lcd_read(struct inode *inode, struct file *file, char *buf, unsigned long count)
536 {
537 	long buttons_now;
538 
539 	if(lcd_waiters > 0)
540 		return -EINVAL;
541 
542 	lcd_waiters++;
543 	while(((buttons_now = (long)button_pressed()) == 0) &&
544 	      !(signal_pending(current))) {
545 		current->state = TASK_INTERRUPTIBLE;
546 		schedule_timeout(2 * HZ);
547 	}
548 	lcd_waiters--;
549 
550 	if(signal_pending(current))
551 		return -ERESTARTSYS;
552 	return buttons_now;
553 }
554 
555 /*
556  *	The various file operations we support.
557  */
558 
559 static struct file_operations lcd_fops = {
560 	read:		lcd_read,
561 	ioctl:		lcd_ioctl,
562 	open:		lcd_open,
563 };
564 
565 static struct miscdevice lcd_dev = {
566 	MISC_DYNAMIC_MINOR,
567 	"lcd",
568 	&lcd_fops
569 };
570 
lcd_init(void)571 int lcd_init(void)
572 {
573 unsigned long data;
574 
575 	printk("%s\n", LCD_DRIVER);
576 	misc_register(&lcd_dev);
577 
578 	/* Check region? Naaah! Just snarf it up. */
579 /*	request_region(RTC_PORT(0), RTC_IO_EXTENT, "lcd");*/
580 
581 	udelay(150);
582 	data = LCDReadData;
583 	if ( (data & 0x000000FF) == (0x00) ) {
584 		lcd_present = 0;
585 		printk("LCD Not Present\n");
586 	        }
587 	else {
588 		lcd_present = 1;
589 		WRITE_GAL( kGal_DevBank2PReg, kGal_DevBank2Cfg );
590 		WRITE_GAL( kGal_DevBank3PReg, kGal_DevBank3Cfg );
591 		}
592 
593 	return 0;
594 }
595 
596 
597 //
598 // Function: dqpoll
599 //
600 // Description:  Polls the data lines to see if the flash is busy
601 //
602 // In: address, byte data
603 //
604 // Out: 0 = busy, 1 = write or erase complete
605 //
606 //
607 
dqpoll(volatile unsigned long address,volatile unsigned char data)608 int dqpoll( volatile unsigned long address, volatile unsigned char data ) {
609 
610 volatile unsigned char dq7;
611 
612 dq7 = data & 0x80;
613 
614 return ( (READ_FLASH(address) & 0x80) == dq7  );
615 
616 }
617 
618 
619 //
620 // Function: timeout
621 //
622 // Description: Checks to see if erase or write has timed out
623 //              By polling dq5
624 //
625 // In: address
626 //
627 //
628 // Out: 0 = not timed out, 1 = timed out
629 
timeout(volatile unsigned long address)630 int timeout( volatile unsigned long address ) {
631 
632 
633 return (  (READ_FLASH(address) & 0x20) ==  0x20 );
634 
635 }
636 
637 
638 
639