singrdk/base/Kernel/Native/HalKdUartIop348.cpp

241 lines
7.0 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// HalKdUartIop348.cpp: UART serial transport for IOP348
//
// Note: Kernel Only
//
#include "hal.h"
#include "halkd.h"
//
// Debugger Debugging
//
#define KDDBG if (0) kdprintf
#define KDDBG2 if (0) kdprintf
//
// Status Constants for reading data from comport
//
#define CP_GET_SUCCESS 0
#define CP_GET_NODATA 1
#define CP_GET_ERROR 2
#define IOP348_UART1_BASE 0xffd82300
#define IOP348_UART2_BASE 0xffd82340
///////////////////////////////////////////////////////////////// Serial Port.
//
#define IOP348_CLOCK_RATE 2083375
#define IOP348_CONTROL_PADCONF_UART1_TX (0x17c)
#define IOP348_CONTROL_PADCONF_UART1_CTS (0x180)
#define IOP348_CONTROL_PADCONF_UART2_TX (0x178)
#define IOP348_CONTROL_PADCONF_UART2_CTS (0x174)
// Define COM Port registers.
#define COM_DAT 0x00
#define COM_DLL 0x00 // Divisor Latch (LSB).
#define COM_IEN 0x01 // Interrupt enable register
#define COM_DLM 0x01 // Divisor Latch (MSB).
#define COM_FCR 0x02 // FIFO Control Register.
#define COM_LCR 0x03 // Line Control Register.
#define COM_MCR 0x04 // Modem Control Register.
#define COM_LSR 0x05 // Line Status Register.
#define COM_MSR 0x06 // Modem Status Register.
#define COM_SCR 0x07 // Scratch Register.
#define IOP348_UART_MDR1 0x8
#define IOP348_UART_IER 0x1
#define IOP348_UART_EFR 0x2
// Define bits in the Interrupt enable register
#define IEN_UNIT_ENABLE 0x40
// Define bits in the FIFO Control Register (FCR).
#define FCR_ENABLE 0x01
#define FCR_CLEAR_RECEIVE 0x02
#define FCR_CLEAR_TRANSMIT 0x04
// Define bits in the Line Control Register (LCR).
#define LCR_DATA_SIZE 0x03
#define LCR_DLAB 0x80
// Define bits in the Modem Control Register (MCR).
#define MCR_DATA_TERMINAL_READY 0x01
#define MCR_REQUEST_TO_SEND 0x02
#define MCR_OUT1 0x04
#define MCR_OUT2 0x08
#define MCR_LOOPBACK 0x10
#define MCR_INITIALIZE (MCR_DATA_TERMINAL_READY | MCR_REQUEST_TO_SEND)
// Define bits in the Line Status Register (LSR).
#define LSR_DATA_AVAILABLE 0x01
#define LSR_OVERRUN_ERROR 0x02
#define LSR_PARITY_ERROR 0x04
#define LSR_FRAMING_ERROR 0x08
#define LSR_BREAK_SIGNAL 0x10
#define LSR_THR_EMPTY 0x20
#define LSR_THR_LINE_IDLE 0x40
// Defined bits in the Modem Status Register (MSR).
#define MSR_DELTA_CLEAR_TO_SEND 0x01
#define MSR_DELTA_DATA_SET_READY 0x02
#define MSR_DELTA_RING_INDICATOR 0x04
#define MSR_DELTA_CARRIER_DETECT 0x08
#define MSR_CLEAR_TO_SEND 0x10
#define MSR_DATA_SET_READY 0x20
#define MSR_RING_INDICATOR 0x40
#define MSR_CARRIER_DETECT 0x80
//
// Communication functions.
//
static const uint32 BaudRate = 115200;
static uint32 *uartBase = 0;
////////////////////////////////////////////////// Serial Port Input & Output.
//
static inline void WriteReg8(volatile void * addr, uint8 value)
{
((volatile uint8 *)addr)[0] = value;
}
static inline uint8 ReadReg8(volatile void * addr)
{
return ((volatile uint8 *)addr)[0];
}
static void UartSetBaudRate(uint32 * BaseAddress, uint32 BaudRate)
{
UINT32 Divisor = 18; // IOP348_CLOCK_RATE / BaudRate;
// Disable UART
WriteReg8(BaseAddress + IOP348_UART_MDR1, 0x7);
// Set register configuration mode B
WriteReg8(BaseAddress + COM_LCR, 0xBF);
// Save enhanced mode
UINT8 Enhanced = ReadReg8(BaseAddress + IOP348_UART_EFR);
WriteReg8(BaseAddress + IOP348_UART_EFR, Enhanced | (1 << 4));
// switch to operational mode
WriteReg8(BaseAddress + COM_LCR, 0);
// clear sleep mode
WriteReg8(BaseAddress + IOP348_UART_IER, 0);
// Set register configuration mode B
WriteReg8(BaseAddress + COM_LCR, 0xBF);
// Write the divisor value to DLL and DLM.
WriteReg8(BaseAddress + COM_DLM, (UINT8)((Divisor >> 8) & 0xff));
WriteReg8(BaseAddress + COM_DLL, (UINT8)(Divisor & 0xff));
// Restore enhanced mode
WriteReg8(BaseAddress + IOP348_UART_EFR, Enhanced);
// Reset the Line Control Register.
WriteReg8(BaseAddress + COM_LCR, LCR_DATA_SIZE);
// Enable UART
WriteReg8(BaseAddress + IOP348_UART_MDR1, 0);
}
bool KdpSerialInit(Class_Microsoft_Singularity_Hal_Platform *nbi)
{
if (nbi->DebugBasePort < 0x100) {
return false;
}
uartBase = (uint32 *)nbi->DebugBasePort;
// Set the default baudrate.
UartSetBaudRate(uartBase, BaudRate);
// Set DLAB to zero. DLAB controls the meaning of the first two
// registers. When zero, the first register is used for all byte transfer
// and the second register controls device interrupts.
//
WriteReg8(uartBase + COM_LCR,
ReadReg8(uartBase + COM_LCR) & ~LCR_DLAB);
// Disable device interrupts. This implementation will handle state
// transitions by request only.
WriteReg8(uartBase + COM_IEN, 0);
// Reset and disable the FIFO queue.
// N.B. FIFO will be reenabled before returning from this routine.
//
WriteReg8(uartBase + COM_FCR, FCR_CLEAR_TRANSMIT | FCR_CLEAR_RECEIVE);
// Configure the Modem Control Register. Disabled device interrupts,
// turn off loopback.
//
WriteReg8(uartBase + COM_MCR,
ReadReg8(uartBase + COM_MCR) & MCR_INITIALIZE);
// Initialize the Modem Control Register. Indicate to the device that
// we are able to send and receive data.
//
WriteReg8(uartBase + COM_MCR, MCR_INITIALIZE);
// Enable the FIFO queues.
WriteReg8(uartBase + COM_FCR, FCR_ENABLE);
// Enable the UART by enabling the UUE bit
WriteReg8(uartBase + COM_IEN, IEN_UNIT_ENABLE);
return true;
}
//
// Define wait timeout value.
//
#define TIMEOUT_COUNT 30 * 1024
// #define TIMEOUT_COUNT 1024 * 200
//#define TIMEOUT_COUNT 15
KDP_STATUS KdpSerialGetByte(OUT PUCHAR Input, BOOL WaitForByte)
{
UINT8 lsr;
UINT8 value;
UINT32 limitcount = WaitForByte ? TIMEOUT_COUNT : 1;
UINT8 msr;
msr = ReadReg8(uartBase + COM_MSR);
while (limitcount != 0) {
limitcount--;
lsr = ReadReg8(uartBase + COM_LSR);
if (lsr & LSR_DATA_AVAILABLE) {
value = ReadReg8(uartBase + COM_DAT);
*Input = (UINT8)(value & 0xff);
return KDP_PACKET_RECEIVED;
}
}
return KDP_PACKET_TIMEOUT;
}
void KdpSerialPutByte(IN UCHAR Output)
{
// Loop until the device is ready for output
while ((ReadReg8(uartBase + COM_LSR) & LSR_THR_EMPTY) == 0) {
}
// The transmitter regiser is clear and can be written to.
WriteReg8(uartBase + COM_DAT, Output);
}
// End of File.