add uarths

This commit is contained in:
hustccc 2020-10-27 22:02:44 +09:00
parent 11397da1d0
commit ca1172b60e
7 changed files with 323 additions and 9 deletions

View File

@ -184,7 +184,7 @@ void plicinit(void);
void plicinithart(void);
int plic_claim(void);
void plic_complete(int);
void device_init(unsigned long);
void device_init(unsigned long, uint64);
// virtio_disk.c
void virtio_disk_init(void);

View File

@ -25,7 +25,7 @@ main(unsigned long hartid, unsigned long dtb_pa)
trapinithart(); // install kernel trap vector
timerinit(); // set up timer interrupt handler
procinit();
device_init(dtb_pa);
device_init(dtb_pa, hartid);
// plicinit(); // set up interrupt controller
// plicinithart(); // ask PLIC for device interrupts
// binit(); // buffer cache

View File

@ -22,12 +22,15 @@
#define UART0 0x38000000L
#define UART0_IRQ 10
#define UARTHS 0x38000000L
#define UARTHS_IRQ 33
// virtio mmio interface
#define VIRTIO0 0x10001000
#define VIRTIO0_IRQ 1
// local interrupt controller, which contains the timer.
#define CLINT 0x2000000L
#define CLINT 0x02000000L
#define CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8*(hartid))
#define CLINT_MTIME (CLINT + 0xBFF8) // cycles since boot.

View File

@ -48,12 +48,12 @@ plic_complete(int irq)
*(uint32*)PLIC_SCLAIM(hart) = irq;
}
void device_init(unsigned long pa) {
void device_init(unsigned long pa, uint64 hartid) {
// after RustSBI, txen = rxen = 1, rxie = 1, rxcnt = 0
// start UART interrupt configuration
// disable external interrupt on hart1 by setting threshold
uint32 *hart0_m_threshold = (uint32*)0x0c200000;
uint32 *hart1_m_threshold = (uint32*)0x0c202000;
uint32 *hart0_m_threshold = (uint32*)PLIC;
uint32 *hart1_m_threshold = (uint32*)PLIC_MENABLE(hartid);
*(hart0_m_threshold) = 0;
*(hart1_m_threshold) = 1;
// *(uint32*)0x0c200000 = 0;
@ -64,7 +64,7 @@ void device_init(unsigned long pa) {
// if(*(uint32*)(0x0c000000 + 33 * 4) != 1) panic("uarhs's priority is not 1\n");
// printf("uart priority: %p\n", *(uint32*)(0x0c000000 + 33 * 4));
// *(uint32*)(0x0c000000 + 33 * 4) = 0x1;
uint32 *hart0_m_int_enable_hi = (uint32*)0x0c002004;
uint32 *hart0_m_int_enable_hi = (uint32*)(PLIC_MENABLE(hartid) + 0x04);
*(hart0_m_int_enable_hi) = (1 << 0x1);
// *(uint32*)0x0c002004 = (1 << 0x1);
sbi_set_extern_interrupt((uint64)supervisor_external_handler - 0xffffffff00000000);

View File

@ -5,6 +5,8 @@
#include "riscv.h"
#include "defs.h"
#include "sbi.h"
#include "memlayout.h"
#include "uarths.h"
static int tick = 0;
@ -34,6 +36,11 @@ void timer_tick() {
tick++;
if((tick % 10) == 0) {
printf("[Timer]tick: %d\n", tick);
sbi_console_putchar(*(uint32*)0x38000004);
uint32 c = *(uint32*)(UARTHS + UARTHS_REG_RXFIFO);
if(c <= 255) {
printf("[UARTHS]receive: %p, ", c);
sbi_console_putchar(c);
printf("\n");
}
}
}

View File

@ -234,5 +234,12 @@ devintr()
void
supervisor_external_handler() {
int irq = *(uint32*)(PLIC + 0x04);
if(irq == UARTHS_IRQ) {
// UARTHS
}
else
{
while (1);
}
}

297
kernel/uarths.h Normal file
View File

@ -0,0 +1,297 @@
/* Copyright 2018 Canaan Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* @brief Universal Asynchronous Receiver/Transmitter (UART)
*
* The UART peripheral supports the following features:
*
* - 8-N-1 and 8-N-2 formats: 8 data bits, no parity bit, 1 start
* bit, 1 or 2 stop bits
*
* - 8-entry transmit and receive FIFO buffers with programmable
* watermark interrupts
*
* - 16× Rx oversampling with 2/3 majority voting per bit
*
* The UART peripheral does not support hardware flow control or
* other modem control signals, or synchronous serial data
* tranfesrs.
*
* @note UART RAM Layout
*
* | Address | Name | Description |
* |-----------|----------|---------------------------------|
* | 0x000 | txdata | Transmit data register |
* | 0x004 | rxdata | Receive data register |
* | 0x008 | txctrl | Transmit control register |
* | 0x00C | rxctrl | Receive control register |
* | 0x010 | ie | UART interrupt enable |
* | 0x014 | ip | UART Interrupt pending |
* | 0x018 | div | Baud rate divisor |
*
*/
#include "types.h"
#ifndef _DRIVER_UARTHS_H
#define _DRIVER_UARTHS_H
#ifdef __cplusplus
extern "C" {
#endif
/* clang-format off */
/* Register address offsets */
#define UARTHS_REG_TXFIFO (0x00)
#define UARTHS_REG_RXFIFO (0x04)
#define UARTHS_REG_TXCTRL (0x08)
#define UARTHS_REG_RXCTRL (0x0c)
#define UARTHS_REG_IE (0x10)
#define UARTHS_REG_IP (0x14)
#define UARTHS_REG_DIV (0x18)
/* TXCTRL register */
#define UARTHS_TXEN (0x01)
#define UARTHS_TXWM(x) (((x) & 0xffff) << 16)
/* RXCTRL register */
#define UARTHS_RXEN (0x01)
#define UARTHS_RXWM(x) (((x) & 0xffff) << 16)
/* IP register */
#define UARTHS_IP_TXWM (0x01)
#define UARTHS_IP_RXWM (0x02)
/* clang-format on */
typedef struct _uarths_txdata
{
/* Bits [7:0] is data */
uint32 data : 8;
/* Bits [30:8] is 0 */
uint32 zero : 23;
/* Bit 31 is full status */
uint32 full : 1;
} __attribute__((packed, aligned(4))) uarths_txdata_t;
typedef struct _uarths_rxdata
{
/* Bits [7:0] is data */
uint32 data : 8;
/* Bits [30:8] is 0 */
uint32 zero : 23;
/* Bit 31 is empty status */
uint32 empty : 1;
} __attribute__((packed, aligned(4))) uarths_rxdata_t;
typedef struct _uarths_txctrl
{
/* Bit 0 is txen, controls whether the Tx channel is active. */
uint32 txen : 1;
/* Bit 1 is nstop, 0 for one stop bit and 1 for two stop bits */
uint32 nstop : 1;
/* Bits [15:2] is reserved */
uint32 resv0 : 14;
/* Bits [18:16] is threshold of interrupt triggers */
uint32 txcnt : 3;
/* Bits [31:19] is reserved */
uint32 resv1 : 13;
} __attribute__((packed, aligned(4))) uarths_txctrl_t;
typedef struct _uarths_rxctrl
{
/* Bit 0 is txen, controls whether the Tx channel is active. */
uint32 rxen : 1;
/* Bits [15:1] is reserved */
uint32 resv0 : 15;
/* Bits [18:16] is threshold of interrupt triggers */
uint32 rxcnt : 3;
/* Bits [31:19] is reserved */
uint32 resv1 : 13;
} __attribute__((packed, aligned(4))) uarths_rxctrl_t;
typedef struct _uarths_ip
{
/* Bit 0 is txwm, raised less than txcnt */
uint32 txwm : 1;
/* Bit 1 is txwm, raised greater than rxcnt */
uint32 rxwm : 1;
/* Bits [31:2] is 0 */
uint32 zero : 30;
} __attribute__((packed, aligned(4))) uarths_ip_t;
typedef struct _uarths_ie
{
/* Bit 0 is txwm, raised less than txcnt */
uint32 txwm : 1;
/* Bit 1 is txwm, raised greater than rxcnt */
uint32 rxwm : 1;
/* Bits [31:2] is 0 */
uint32 zero : 30;
} __attribute__((packed, aligned(4))) uarths_ie_t;
typedef struct _uarths_div
{
/* Bits [31:2] is baud rate divisor register */
uint32 div : 16;
/* Bits [31:16] is 0 */
uint32 zero : 16;
} __attribute__((packed, aligned(4))) uarths_div_t;
typedef struct _uarths
{
/* Address offset 0x00 */
uarths_txdata_t txdata;
/* Address offset 0x04 */
uarths_rxdata_t rxdata;
/* Address offset 0x08 */
uarths_txctrl_t txctrl;
/* Address offset 0x0c */
uarths_rxctrl_t rxctrl;
/* Address offset 0x10 */
uarths_ie_t ie;
/* Address offset 0x14 */
uarths_ip_t ip;
/* Address offset 0x18 */
uarths_div_t div;
} __attribute__((packed, aligned(4))) uarths_t;
typedef enum _uarths_interrupt_mode
{
UARTHS_SEND = 1,
UARTHS_RECEIVE = 2,
UARTHS_SEND_RECEIVE = 3,
} uarths_interrupt_mode_t;
typedef enum _uarths_stopbit
{
UARTHS_STOP_1,
UARTHS_STOP_2
} uarths_stopbit_t;
extern volatile uarths_t *const uarths;
/**
* @brief Initialization Core UART
*
* @return result
* - 0 Success
* - Other Fail
*/
void uarths_init(void);
/**
* @brief Put a char to UART
*
* @param[in] c The char to put
*
* @return result
* - Byte On success, returns the written character.
* - EOF On failure, returns EOF and sets the error indicator (see ferror()) on stdout.
*/
int uarths_putchar(char c);
/**
* @brief Get a byte from UART
*
* @return byte as int type from UART
* - Byte The character read as an unsigned char cast to an int
* - EOF EOF on end of file or error, no enough byte to read
*/
int uarths_getchar(void);
/**
* @brief Send a string to UART
*
* @param[in] s The string to send
*
* @note The string must ending with '\0'
*
* @return result
* - 0 Success
* - Other Fail
*/
int uarths_puts(const char *s);
/**
* @brief [Deprecated] Get a byte from UART
*
* @return byte as int type from UART
* - Byte The character read as an unsigned char cast to an int
* - EOF EOF on end of file or error, no enough byte to read
*/
int uarths_getc(void);
/**
* @brief Set uarths interrupt callback
*
* @param[in] interrupt_mode Interrupt mode recevice or send
* @param[in] uarths_callback Interrupt callback
* @param[in] ctx Param of callback
* @param[in] priority Interrupt priority
*
*/
/**
* @brief Uarths receive data
*
* @param[in] buf The data received
* @param[in] buf_len The length of data
*
* @return Number of received data
*/
uint64 uarths_receive_data(uint8 *buf, uint64 buf_len);
/**
* @brief Uarths receive data
*
* @param[in] buf The data sended
* @param[in] buf_len The length of data
*
* @return Number of sended data
*/
uint64 uarths_send_data(const uint8 *buf, uint64 buf_len);
/**
* @brief Get interrupt mode
*
* @return Mode of interrupt
*/
uarths_interrupt_mode_t uarths_get_interrupt_mode(void);
/**
* @brief Set uarths baud rate and stopbit
*
* @param[in] baud_rate The baud rate
* @param[in] stopbit The stopbit of data
*
*/
void uarths_config(uint32 baud_rate, uarths_stopbit_t stopbit);
/**
* @brief Set uart interrupt condition
*
* @param[in] interrupt_mode The interrupt mode
* @param[in] cnt The count of tigger
*
*/
void uarths_set_interrupt_cnt(uarths_interrupt_mode_t interrupt_mode, uint8 cnt);
#ifdef __cplusplus
}
#endif
#endif /* _DRIVER_UARTHS_H */