1/* 2 * Console via Blackfin JTAG Communication 3 * 4 * Copyright 2008-2011 Analog Devices Inc. 5 * 6 * Enter bugs at http://blackfin.uclinux.org/ 7 * 8 * Licensed under the GPL-2 or later. 9 */ 10 11#include <linux/console.h> 12#include <linux/delay.h> 13#include <linux/err.h> 14#include <linux/init.h> 15#include <linux/moduleparam.h> 16#include <linux/types.h> 17 18#include "hvc_console.h" 19 20/* See the Debug/Emulation chapter in the HRM */ 21#define EMUDOF 0x00000001 /* EMUDAT_OUT full & valid */ 22#define EMUDIF 0x00000002 /* EMUDAT_IN full & valid */ 23#define EMUDOOVF 0x00000004 /* EMUDAT_OUT overflow */ 24#define EMUDIOVF 0x00000008 /* EMUDAT_IN overflow */ 25 26/* Helper functions to glue the register API to simple C operations */ 27static inline uint32_t bfin_write_emudat(uint32_t emudat) 28{ 29 __asm__ __volatile__("emudat = %0;" : : "d"(emudat)); 30 return emudat; 31} 32 33static inline uint32_t bfin_read_emudat(void) 34{ 35 uint32_t emudat; 36 __asm__ __volatile__("%0 = emudat;" : "=d"(emudat)); 37 return emudat; 38} 39 40/* Send data to the host */ 41static int hvc_bfin_put_chars(uint32_t vt, const char *buf, int count) 42{ 43 static uint32_t outbound_len; 44 uint32_t emudat; 45 int ret; 46 47 if (bfin_read_DBGSTAT() & EMUDOF) 48 return 0; 49 50 if (!outbound_len) { 51 outbound_len = count; 52 bfin_write_emudat(outbound_len); 53 return 0; 54 } 55 56 ret = min(outbound_len, (uint32_t)4); 57 memcpy(&emudat, buf, ret); 58 bfin_write_emudat(emudat); 59 outbound_len -= ret; 60 61 return ret; 62} 63 64/* Receive data from the host */ 65static int hvc_bfin_get_chars(uint32_t vt, char *buf, int count) 66{ 67 static uint32_t inbound_len; 68 uint32_t emudat; 69 int ret; 70 71 if (!(bfin_read_DBGSTAT() & EMUDIF)) 72 return 0; 73 emudat = bfin_read_emudat(); 74 75 if (!inbound_len) { 76 inbound_len = emudat; 77 return 0; 78 } 79 80 ret = min(inbound_len, (uint32_t)4); 81 memcpy(buf, &emudat, ret); 82 inbound_len -= ret; 83 84 return ret; 85} 86 87/* Glue the HVC layers to the Blackfin layers */ 88static const struct hv_ops hvc_bfin_get_put_ops = { 89 .get_chars = hvc_bfin_get_chars, 90 .put_chars = hvc_bfin_put_chars, 91}; 92 93static int __init hvc_bfin_console_init(void) 94{ 95 hvc_instantiate(0, 0, &hvc_bfin_get_put_ops); 96 return 0; 97} 98console_initcall(hvc_bfin_console_init); 99 100static int __init hvc_bfin_init(void) 101{ 102 hvc_alloc(0, 0, &hvc_bfin_get_put_ops, 128); 103 return 0; 104} 105device_initcall(hvc_bfin_init); 106