├── doc ├── netv2_schematic.pdf └── netv2mvp_schematic.pdf ├── firmware ├── bist.h ├── ci.h ├── hdmi_out0.h ├── stdio_wrap.h ├── dump.h ├── asm.h ├── config.h ├── isr.c ├── stdio_wrap.c ├── config.c ├── hdmi_in0.h ├── hdmi_in1.h ├── i2c.h ├── edid.h ├── pattern.h ├── linker.ld ├── processor.h ├── flags.h ├── encoder.h ├── Makefile ├── mmcm.h ├── main.c ├── bist.c ├── hdmi_out0.c ├── i2c.c ├── dump.c ├── pattern.c ├── encoder.c ├── edid.c ├── hdmi_in0.c ├── hdmi_in1.c ├── processor.c └── ci.c ├── litescope ├── analyzer.csv ├── test_io.py ├── test_analyzer.py~ ├── test_analyzer.py ├── csr.csv ├── build.py~ └── build.py ├── load.py ├── software └── pcie │ ├── kernel │ ├── init.sh │ ├── README │ ├── flags.h │ ├── config.h │ ├── Makefile │ ├── litepcie.h │ └── main.c │ └── user │ ├── Makefile │ ├── cutils.h │ ├── litepcie_lib.h │ ├── litepcie_lib.c │ └── litepcie_util.c ├── TODO ├── test └── test_identifier.py ├── README ├── gateware └── dma.py ├── dma_test.py ├── netv2.py └── reverse.py /doc/netv2_schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bunnie/netv2-soc/HEAD/doc/netv2_schematic.pdf -------------------------------------------------------------------------------- /doc/netv2mvp_schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bunnie/netv2-soc/HEAD/doc/netv2mvp_schematic.pdf -------------------------------------------------------------------------------- /firmware/bist.h: -------------------------------------------------------------------------------- 1 | #ifndef __BIST_H 2 | #define __BIST_H 3 | 4 | void bist_test(void); 5 | 6 | #endif /* __BIST_H */ 7 | -------------------------------------------------------------------------------- /litescope/analyzer.csv: -------------------------------------------------------------------------------- 1 | config,None,dw,128 2 | config,None,depth,512 3 | config,None,cd_ratio,1 4 | signal,0,bus,128 5 | -------------------------------------------------------------------------------- /firmware/ci.h: -------------------------------------------------------------------------------- 1 | #ifndef __CI_H 2 | #define __CI_H 3 | 4 | void ci_prompt(void); 5 | void ci_service(void); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /load.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from litex.build.xilinx import VivadoProgrammer 3 | 4 | prog = VivadoProgrammer() 5 | prog.load_bitstream("build/gateware/top.bit") 6 | -------------------------------------------------------------------------------- /firmware/hdmi_out0.h: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef CSR_HDMI_OUT0_I2C_W_ADDR 3 | 4 | void hdmi_out0_i2c_init(void); 5 | void hdmi_out0_print_edid(void); 6 | 7 | #endif -------------------------------------------------------------------------------- /firmware/stdio_wrap.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int wputs(const char *s); 4 | int wprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 5 | void wputsnonl(const char *s); 6 | -------------------------------------------------------------------------------- /software/pcie/kernel/init.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # TODO: use udev instead 3 | 4 | insmod litepcie.ko 5 | 6 | major=$(awk '/ litepcie$/{print $1}' /proc/devices) 7 | mknod -m 666 /dev/litepcie0 c $major 0 8 | -------------------------------------------------------------------------------- /software/pcie/kernel/README: -------------------------------------------------------------------------------- 1 | - Use 'make' to build the driver 2 | 3 | - Install the driver and create the device with : 4 | 5 | ./init.sh 6 | 7 | - Remove driver with 8 | 9 | rmmod litepcie 10 | -------------------------------------------------------------------------------- /firmware/dump.h: -------------------------------------------------------------------------------- 1 | #ifndef __DUMP_H 2 | #define __DUMP_H 3 | 4 | void mr(char *startaddr, char *len); 5 | void mw(char *addr, char *value, char *count); 6 | void mc(char *dstaddr, char *srcaddr, char *count); 7 | 8 | #endif -------------------------------------------------------------------------------- /software/pcie/kernel/flags.h: -------------------------------------------------------------------------------- 1 | #ifndef __HW_FLAGS_H 2 | #define __HW_FLAGS_H 3 | 4 | /* dma */ 5 | #define DMA_LOOPBACK_ENABLE 0x1 6 | 7 | #define DMA_TABLE_LOOP_INDEX 1 << 0 8 | #define DMA_TABLE_LOOP_COUNT 1 << 16 9 | 10 | #endif /* __HW_FLAGS_H */ 11 | -------------------------------------------------------------------------------- /firmware/asm.h: -------------------------------------------------------------------------------- 1 | #ifdef __lm32__ 2 | 3 | #define REBOOT __asm__("call r0") 4 | #define NOP __asm__("nop") 5 | 6 | #elif __or1k__ 7 | 8 | #define REBOOT __asm__("l.j 0") 9 | #define NOP __asm__("l.nop") 10 | 11 | #else 12 | 13 | #error "Unknown ARCH." 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /software/pcie/kernel/config.h: -------------------------------------------------------------------------------- 1 | #ifndef __HW_CONFIG_H 2 | #define __HW_CONFIG_H 3 | 4 | /* pci */ 5 | #define PCI_FPGA_VENDOR_ID 0x10ee 6 | #define PCI_FPGA_DEVICE_ID 0x7022 7 | #define PCI_FPGA_BAR0_SIZE 0xa000 8 | 9 | /* dma */ 10 | #define DMA_BUFFER_COUNT 128 11 | 12 | 13 | #endif /* __HW_CONFIG_H */ 14 | -------------------------------------------------------------------------------- /software/pcie/kernel/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for kernel module 2 | 3 | KERNEL_VERSION:=$(shell uname -r) 4 | KERNEL_PATH:=/lib/modules/$(KERNEL_VERSION)/build 5 | 6 | obj-m = litepcie.o 7 | litepcie-objs = main.o 8 | 9 | all: litepcie.ko 10 | 11 | litepcie.ko: main.c 12 | make -C $(KERNEL_PATH) M=$(PWD) modules 13 | 14 | clean: 15 | make -C $(KERNEL_PATH) M=$(PWD) clean 16 | rm -f *~ 17 | -------------------------------------------------------------------------------- /software/pcie/user/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-O2 -Wall -g -I../kernel -MMD 2 | LDFLAGS=-g 3 | CC=gcc 4 | AR=ar 5 | 6 | PROGS=litepcie_util 7 | 8 | all: $(PROGS) 9 | 10 | litepcie_util: litepcie_util.o litepcie_lib.o 11 | $(CC) $(LDFLAGS) -o $@ $^ -lrt -lm 12 | 13 | clean: 14 | rm -f $(PROGS) *.o *.a *.d *~ 15 | 16 | %.o: %.c 17 | $(CC) -c $(CFLAGS) -o $@ $< 18 | 19 | -include $(wildcard *.d) 20 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - Add real hdmi support to litevideo input. (at least ignore specific hdmi data) 2 | - Inject captured hdmi data into litevideo input, simulate. 3 | - Test real hdmi support on board. 4 | - Add second HDMI in/out ports to NeTV2MVP. 5 | - Test Host Memory <--> DDR3 DMAs 6 | - Test Host Memory --> DDR3 --> VideoOut 7 | - Test VideoIn --> DDR3 --> Host Memory 8 | - Test PCIe Gen2 X4 (requires LitePCIe changes). -------------------------------------------------------------------------------- /test/test_identifier.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from litex.soc.tools.remote import RemoteClient 4 | 5 | wb = RemoteClient() 6 | wb.open() 7 | 8 | # # # 9 | 10 | # get identifier 11 | fpga_id = "" 12 | for i in range(256): 13 | c = chr(wb.read(wb.bases.identifier_mem + 4*i) & 0xff) 14 | fpga_id += c 15 | if c == "\0": 16 | break 17 | print("fpga_id: " + fpga_id) 18 | 19 | # # # 20 | 21 | wb.close() 22 | -------------------------------------------------------------------------------- /firmware/config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H 2 | #define __CONFIG_H 3 | 4 | enum { 5 | CONFIG_KEY_RESOLUTION = 0, 6 | CONFIG_KEY_BLEND_USER1, 7 | CONFIG_KEY_BLEND_USER2, 8 | CONFIG_KEY_BLEND_USER3, 9 | CONFIG_KEY_BLEND_USER4, 10 | 11 | CONFIG_KEY_COUNT 12 | }; 13 | 14 | #define CONFIG_DEFAULTS { 12, 1, 2, 3, 4 } 15 | 16 | void config_init(void); 17 | void config_write_all(void); 18 | unsigned char config_get(unsigned char key); 19 | void config_set(unsigned char key, unsigned char value); 20 | 21 | #endif /* __CONFIG_H */ 22 | -------------------------------------------------------------------------------- /litescope/test_io.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from litex.soc.tools.remote import RemoteClient 4 | 5 | from litescope import LiteScopeIODriver 6 | 7 | 8 | def led_anim(inout): 9 | import time 10 | for i in range(10): 11 | io.write(0xa5) 12 | time.sleep(0.1) 13 | io.write(0x5a) 14 | time.sleep(0.1) 15 | 16 | 17 | wb = RemoteClient() 18 | wb.open() 19 | 20 | # # # 21 | 22 | io = LiteScopeIODriver(wb.regs, "io") 23 | led_anim(io) 24 | print("{:04x}".format(io.read())) 25 | 26 | # # # 27 | 28 | wb.close() 29 | -------------------------------------------------------------------------------- /firmware/isr.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "hdmi_in0.h" 6 | #include "hdmi_in1.h" 7 | void isr(void); 8 | void isr(void) 9 | { 10 | unsigned int irqs; 11 | 12 | irqs = irq_pending() & irq_getmask(); 13 | 14 | if(irqs & (1 << UART_INTERRUPT)) 15 | uart_isr(); 16 | 17 | #ifdef CSR_HDMI_IN0_INTERRUPT 18 | if(irqs & (1 << HDMI_IN0_INTERRUPT)) 19 | hdmi_in0_isr(); 20 | #endif 21 | #ifdef HDMI_IN1_INTERRUPT 22 | if(irqs & (1 << HDMI_IN1_INTERRUPT)) { 23 | hdmi_in1_isr(); 24 | } 25 | #endif 26 | } 27 | -------------------------------------------------------------------------------- /firmware/stdio_wrap.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "stdio_wrap.h" 8 | 9 | int wputs(const char *s) 10 | { 11 | puts(s); 12 | return 0; 13 | } 14 | 15 | int wprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 16 | int wprintf(const char *fmt, ...) 17 | { 18 | int len; 19 | va_list args; 20 | va_start(args, fmt); 21 | len = vprintf(fmt, args); 22 | va_end(args); 23 | return len; 24 | } 25 | 26 | void wputsnonl(const char *s) 27 | { 28 | putsnonl(s); 29 | } -------------------------------------------------------------------------------- /software/pcie/user/cutils.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifndef _BOOL_defined 6 | #define _BOOL_defined 7 | #undef FALSE 8 | #undef TRUE 9 | 10 | typedef int BOOL; 11 | enum { 12 | FALSE = 0, 13 | TRUE = 1, 14 | }; 15 | #endif 16 | 17 | static inline int sub_mod_int(int a, int b, int m) 18 | { 19 | a -= b; 20 | if (a < 0) 21 | a += m; 22 | return a; 23 | } 24 | 25 | static inline int add_mod_int(int a, int b, int m) 26 | { 27 | a += b; 28 | if (a >= m) 29 | a -= m; 30 | return a; 31 | } 32 | -------------------------------------------------------------------------------- /firmware/config.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "config.h" 6 | 7 | static const unsigned char config_defaults[CONFIG_KEY_COUNT] = CONFIG_DEFAULTS; 8 | static unsigned char config_values[CONFIG_KEY_COUNT]; 9 | 10 | void config_init(void) 11 | { 12 | memcpy(config_values, config_defaults, CONFIG_KEY_COUNT); 13 | } 14 | 15 | void config_write_all(void) 16 | { 17 | } 18 | 19 | unsigned char config_get(unsigned char key) 20 | { 21 | return config_values[key]; 22 | } 23 | 24 | void config_set(unsigned char key, unsigned char value) 25 | { 26 | } 27 | -------------------------------------------------------------------------------- /firmware/hdmi_in0.h: -------------------------------------------------------------------------------- 1 | #ifndef __HDMI_IN0_H 2 | #define __HDMI_IN0_H 3 | 4 | extern int hdmi_in0_debug; 5 | extern int hdmi_in0_fb_index; 6 | 7 | unsigned int hdmi_in0_framebuffer_base(char n); 8 | 9 | void hdmi_in0_isr(void); 10 | void hdmi_in0_init_video(int hres, int vres); 11 | void hdmi_in0_disable(void); 12 | void hdmi_in0_clear_framebuffers(void); 13 | void hdmi_in0_print_status(void); 14 | int hdmi_in0_calibrate_delays(int freq); 15 | int hdmi_in0_adjust_phase(void); 16 | int hdmi_in0_init_phase(void); 17 | int hdmi_in0_phase_startup(int freq); 18 | void hdmi_in0_service(int freq); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /firmware/hdmi_in1.h: -------------------------------------------------------------------------------- 1 | #ifndef __HDMI_IN1_H 2 | #define __HDMI_IN1_H 3 | 4 | extern int hdmi_in1_debug; 5 | extern int hdmi_in1_fb_index; 6 | 7 | unsigned int hdmi_in1_framebuffer_base(char n); 8 | 9 | void hdmi_in1_isr(void); 10 | void hdmi_in1_init_video(int hres, int vres); 11 | void hdmi_in1_disable(void); 12 | void hdmi_in1_clear_framebuffers(void); 13 | void hdmi_in1_print_status(void); 14 | int hdmi_in1_calibrate_delays(int freq); 15 | int hdmi_in1_adjust_phase(void); 16 | int hdmi_in1_init_phase(void); 17 | int hdmi_in1_phase_startup(int freq); 18 | void hdmi_in1_service(int freq); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /litescope/test_analyzer.py~: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import time 3 | 4 | from litex.soc.tools.remote import RemoteClient 5 | from litescope.software.driver.analyzer import LiteScopeAnalyzerDriver 6 | 7 | wb = RemoteClient() 8 | wb.open() 9 | 10 | # # # 11 | 12 | analyzer = LiteScopeAnalyzerDriver(wb.regs, "analyzer", debug=True) 13 | #analyzer.configure_trigger(cond={"charsync0_data": 0x354}) 14 | analyzer.configure_trigger(cond={"hdmi_in0_frame_de" : 1}) 15 | 16 | analyzer.configure_subsampler(1) 17 | analyzer.run(offset=32, length=256) 18 | analyzer.wait_done() 19 | analyzer.upload() 20 | analyzer.save("dump.vcd") 21 | 22 | # # # 23 | 24 | wb.close() 25 | -------------------------------------------------------------------------------- /firmware/i2c.h: -------------------------------------------------------------------------------- 1 | #ifndef __I2C_H 2 | #define __I2C_H 3 | 4 | #define I2C_SCL 0x01 5 | #define I2C_SDAOE 0x02 6 | #define I2C_SDAOUT 0x04 7 | 8 | #define I2C_SDAIN 0x01 9 | 10 | typedef unsigned char (*i2c_w_read_t)(void); 11 | typedef void (*i2c_w_write_t)(unsigned char value); 12 | typedef unsigned char (*i2c_r_read_t)(void); 13 | 14 | typedef struct { 15 | i2c_w_read_t w_read; 16 | i2c_w_write_t w_write; 17 | i2c_r_read_t r_read; 18 | int started; 19 | } I2C; 20 | 21 | int i2c_init(I2C *i2c); 22 | void i2c_delay(void); 23 | unsigned int i2c_read_bit(I2C *i2c); 24 | void i2c_write_bit(I2C *i2c, unsigned int bit); 25 | void i2c_start_cond(I2C *i2c); 26 | void i2c_stop_cond(I2C *i2c); 27 | unsigned int i2c_write(I2C *i2c, unsigned char byte); 28 | unsigned char i2c_read(I2C *i2c, int ack); 29 | 30 | #endif /* __I2C_H */ 31 | -------------------------------------------------------------------------------- /firmware/edid.h: -------------------------------------------------------------------------------- 1 | #ifndef __EDID_H 2 | #define __EDID_H 3 | 4 | #define MAX_MONITOR_NAME_LEN 13 5 | 6 | struct video_timing { 7 | unsigned int pixel_clock; /* in tens of kHz */ 8 | 9 | unsigned int h_active; 10 | unsigned int h_blanking; 11 | unsigned int h_sync_offset; 12 | unsigned int h_sync_width; 13 | 14 | unsigned int v_active; 15 | unsigned int v_blanking; 16 | unsigned int v_sync_offset; 17 | unsigned int v_sync_width; 18 | 19 | unsigned int established_timing; 20 | const char* comment; 21 | }; 22 | 23 | int validate_edid(const void *buf); 24 | void get_monitor_name(const void *buf, char *name); 25 | void generate_edid(void *out, 26 | const char mfg_name[3], const char product_code[2], int year, 27 | const char *name, 28 | const struct video_timing *timing); 29 | 30 | unsigned calculate_refresh_rate(const struct video_timing* video_mode); 31 | 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /litescope/test_analyzer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import time 3 | import os 4 | import sys 5 | 6 | from litex.gen.fhdl.structure import * 7 | 8 | from litex.soc.tools.remote import RemoteClient 9 | from litescope.software.driver.analyzer import LiteScopeAnalyzerDriver 10 | 11 | wb = RemoteClient() 12 | wb.open() 13 | 14 | # # # 15 | 16 | analyzer = LiteScopeAnalyzerDriver(wb.regs, "analyzer", debug=True) 17 | #analyzer.configure_trigger(cond={"charsync0_data": 0x354}) 18 | #analyzer.configure_trigger(cond={"hdmi_in0_frame_de" : 1}) 19 | #analyzer.configure_trigger(cond={}) 20 | t = getattr(analyzer, "frontend_trigger_value") 21 | m = getattr(analyzer, "frontend_trigger_mask") 22 | t.write(0x80000000000000000) 23 | m.write(0x80000000000000000) 24 | 25 | analyzer.configure_subsampler(1) 26 | analyzer.run(offset=32, length=512) 27 | analyzer.wait_done() 28 | analyzer.upload() 29 | analyzer.save("dump.vcd") 30 | 31 | # # # 32 | 33 | wb.close() 34 | -------------------------------------------------------------------------------- /firmware/pattern.h: -------------------------------------------------------------------------------- 1 | #ifndef __PATTERN_H 2 | #define __PATTERN_H 3 | 4 | /* Colors in YCBCR422 format (see pattern.py) */ 5 | #define YCBCR422_WHITE 0x80ff80ff 6 | #define YCBCR422_YELLOW 0x00e194e1 7 | #define YCBCR422_CYAN 0xabb200b2 8 | #define YCBCR422_GREEN 0x2b951595 9 | #define YCBCR422_PURPLE 0xd469e969 10 | #define YCBCR422_RED 0x544cff4c 11 | #define YCBCR422_BLUE 0xff1d6f1d 12 | #define YCBCR422_BLACK 0x80108010 13 | 14 | /* Colors in RGB format */ 15 | #define RGB_WHITE 0x00ffffff 16 | #define RGB_YELLOW 0x0000ffff 17 | #define RGB_CYAN 0x00ffff00 18 | #define RGB_GREEN 0x0000ff00 19 | #define RGB_PURPLE 0x00ff00ff 20 | #define RGB_RED 0x000000ff 21 | #define RGB_BLUE 0x00ff0000 22 | #define RGB_BLACK 0x00000000 23 | 24 | unsigned int pattern_framebuffer_base(void); 25 | 26 | int pattern; 27 | 28 | #define COLOR_BAR_PATTERN 0 29 | #define BLACK_WHITE_BAR_PATTERN 1 30 | 31 | void pattern_fill_framebuffer(int h_active, int m_active); 32 | void pattern_service(void); 33 | 34 | #endif /* __PATTERN_H */ 35 | -------------------------------------------------------------------------------- /firmware/linker.ld: -------------------------------------------------------------------------------- 1 | INCLUDE generated/output_format.ld 2 | ENTRY(_start) 3 | 4 | __DYNAMIC = 0; 5 | 6 | INCLUDE generated/regions.ld 7 | 8 | SECTIONS 9 | { 10 | .text : 11 | { 12 | _ftext = .; 13 | *(.text .stub .text.* .gnu.linkonce.t.*) 14 | _etext = .; 15 | } > main_ram 16 | 17 | .rodata : 18 | { 19 | . = ALIGN(4); 20 | _frodata = .; 21 | *(.rodata .rodata.* .gnu.linkonce.r.*) 22 | *(.rodata1) 23 | _erodata = .; 24 | } > main_ram 25 | 26 | .data : 27 | { 28 | . = ALIGN(4); 29 | _fdata = .; 30 | *(.data .data.* .gnu.linkonce.d.*) 31 | *(.data1) 32 | _gp = ALIGN(16); 33 | *(.sdata .sdata.* .gnu.linkonce.s.*) 34 | _edata = .; 35 | } > main_ram 36 | 37 | .bss : 38 | { 39 | . = ALIGN(4); 40 | _fbss = .; 41 | *(.dynsbss) 42 | *(.sbss .sbss.* .gnu.linkonce.sb.*) 43 | *(.scommon) 44 | *(.dynbss) 45 | *(.bss .bss.* .gnu.linkonce.b.*) 46 | *(COMMON) 47 | . = ALIGN(4); 48 | _ebss = .; 49 | _end = .; 50 | } > sram 51 | } 52 | 53 | PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4); 54 | -------------------------------------------------------------------------------- /firmware/processor.h: -------------------------------------------------------------------------------- 1 | #ifndef __PROCESSOR_H 2 | #define __PROCESSOR_H 3 | 4 | #define PROCESSOR_MODE_COUNT 14 5 | #define PROCESSOR_MODE_DESCLEN 64 6 | 7 | enum { 8 | VIDEO_IN_HDMI_IN0=0, 9 | VIDEO_IN_HDMI_IN1, 10 | VIDEO_IN_PATTERN 11 | }; 12 | 13 | enum { 14 | VIDEO_OUT_HDMI_OUT0=0, 15 | VIDEO_OUT_HDMI_OUT1, 16 | VIDEO_OUT_ENCODER 17 | }; 18 | 19 | extern int processor_mode; 20 | int processor_h_active; 21 | int processor_v_active; 22 | int processor_refresh; 23 | int processor_hdmi_out0_source; 24 | int processor_hdmi_out1_source; 25 | int processor_encoder_source; 26 | char processor_buffer[16]; 27 | 28 | void processor_list_modes(char *mode_descriptors); 29 | void processor_init(void); 30 | void processor_start(int mode); 31 | void processor_set_hdmi_out0_source(int source); 32 | void processor_set_hdmi_out1_source(int source); 33 | void processor_set_encoder_source(int source); 34 | char * processor_get_source_name(int source); 35 | void processor_update(void); 36 | void processor_service(void); 37 | 38 | #endif /* __PROCESSOR_H */ 39 | -------------------------------------------------------------------------------- /firmware/flags.h: -------------------------------------------------------------------------------- 1 | #ifndef __HW_FLAGS_H 2 | #define __HW_FLAGS_H 3 | 4 | #define UART_EV_TX 0x1 5 | #define UART_EV_RX 0x2 6 | 7 | #define DFII_CONTROL_SEL 0x01 8 | #define DFII_CONTROL_CKE 0x02 9 | #define DFII_CONTROL_ODT 0x04 10 | #define DFII_CONTROL_RESET_N 0x08 11 | 12 | #define DFII_COMMAND_CS 0x01 13 | #define DFII_COMMAND_WE 0x02 14 | #define DFII_COMMAND_CAS 0x04 15 | #define DFII_COMMAND_RAS 0x08 16 | #define DFII_COMMAND_WRDATA 0x10 17 | #define DFII_COMMAND_RDDATA 0x20 18 | 19 | #define ETHMAC_EV_SRAM_WRITER 0x1 20 | #define ETHMAC_EV_SRAM_READER 0x1 21 | 22 | #define CLKGEN_STATUS_BUSY 0x1 23 | #define CLKGEN_STATUS_PROGDONE 0x2 24 | #define CLKGEN_STATUS_LOCKED 0x4 25 | 26 | #define DVISAMPLER_TOO_LATE 0x1 27 | #define DVISAMPLER_TOO_EARLY 0x2 28 | 29 | #define DVISAMPLER_DELAY_RST 0x01 30 | #define DVISAMPLER_DELAY_MASTER_INC 0x02 31 | #define DVISAMPLER_DELAY_MASTER_DEC 0x04 32 | #define DVISAMPLER_DELAY_SLAVE_INC 0x08 33 | #define DVISAMPLER_DELAY_SLAVE_DEC 0x10 34 | 35 | #define DVISAMPLER_SLOT_EMPTY 0 36 | #define DVISAMPLER_SLOT_LOADED 1 37 | #define DVISAMPLER_SLOT_PENDING 2 38 | 39 | #endif /* __HW_FLAGS_H */ 40 | -------------------------------------------------------------------------------- /firmware/encoder.h: -------------------------------------------------------------------------------- 1 | #ifndef __ENCODER_H 2 | #define __ENCODER_H 3 | 4 | #define ENCODER_START_REG 0x0 5 | #define ENCODER_IMAGE_SIZE_REG 0x4 6 | #define ENCODER_RAM_ACCESS_REG 0x8 7 | #define ENCODER_STS_REG 0xC 8 | #define ENCODER_COD_DATA_ADDR_REG 0x10 9 | #define ENCODER_LENGTH_REG 0x14 10 | 11 | #define ENCODER_QUANTIZER_RAM_LUMA_BASE 0x100 12 | 13 | const char luma_rom_100[64]; 14 | const char luma_rom_85[64]; 15 | const char luma_rom_75[64]; 16 | const char luma_rom_50[64]; 17 | 18 | #define ENCODER_QUANTIZER_RAM_CHROMA_BASE 0x200 19 | 20 | const char chroma_rom_100[64]; 21 | const char chroma_rom_85[64]; 22 | const char chroma_rom_75[64]; 23 | const char chroma_rom_50[64]; 24 | 25 | char encoder_enabled; 26 | int encoder_target_fps; 27 | int encoder_fps; 28 | int encoder_quality; 29 | 30 | void encoder_write_reg(unsigned int adr, unsigned int value); 31 | unsigned int encoder_read_reg(unsigned int adr); 32 | void encoder_init(int encoder_quality); 33 | void encoder_start(short resx, short resy); 34 | int encoder_done(void); 35 | void encoder_enable(char enable); 36 | int encoder_set_quality(int quality); 37 | int encoder_set_fps(int fps); 38 | void encoder_service(void); 39 | 40 | #endif -------------------------------------------------------------------------------- /firmware/Makefile: -------------------------------------------------------------------------------- 1 | NETV2_DIR=../build 2 | 3 | include $(NETV2_DIR)/software/include/generated/variables.mak 4 | include $(SOC_DIRECTORY)/software/common.mak 5 | 6 | OBJECTS=isr.o \ 7 | config.o \ 8 | processor.o \ 9 | hdmi_in0.o \ 10 | hdmi_in1.o \ 11 | hdmi_out0.o \ 12 | pattern.o \ 13 | edid.o \ 14 | mmcm.o \ 15 | ci.o \ 16 | encoder.o \ 17 | i2c.o \ 18 | main.o \ 19 | bist.o \ 20 | dump.o \ 21 | stdio_wrap.o 22 | 23 | CFLAGS += -I. 24 | 25 | all: firmware.bin 26 | 27 | # pull in dependency info for *existing* .o files 28 | -include $(OBJECTS:.o=.d) 29 | 30 | %.bin: %.elf 31 | $(OBJCOPY) -O binary $< $@ 32 | chmod -x $@ 33 | cp $@ boot.bin 34 | 35 | firmware.elf: $(OBJECTS) 36 | $(LD) $(LDFLAGS) \ 37 | -T linker.ld \ 38 | -N -o $@ \ 39 | $(NETV2_DIR)/software/libbase/crt0-$(CPU).o \ 40 | $(OBJECTS) \ 41 | -L$(NETV2_DIR)/software/libbase \ 42 | -L$(NETV2_DIR)/software/libcompiler_rt \ 43 | -lbase-nofloat -lcompiler_rt 44 | chmod -x $@ 45 | 46 | main.o: main.c 47 | $(compile) 48 | 49 | %.o: %.c 50 | $(compile) 51 | 52 | %.o: %.S 53 | $(assemble) 54 | 55 | load: firmware.bin 56 | litex_term --kernel firmware.bin COM8 57 | 58 | clean: 59 | $(RM) $(OBJECTS) $(OBJECTS:.o=.d) firmware.elf firmware.bin .*~ *~ 60 | 61 | .PHONY: all main.o clean load 62 | -------------------------------------------------------------------------------- /firmware/mmcm.h: -------------------------------------------------------------------------------- 1 | #ifndef __MMCM_H 2 | #define __MMCM_H 3 | 4 | void mmcm_decode_clkreg1(unsigned int data); 5 | void mmcm_decode_clkreg2(unsigned int data); 6 | void mmcm_decode_divreg(unsigned int data); 7 | void mmcm_decode_lockreg1(unsigned int data); 8 | void mmcm_decode_lockreg2(unsigned int data); 9 | void mmcm_decode_lockreg3(unsigned int data); 10 | void mmcm_decode_filtreg1(unsigned int data); 11 | void mmcm_decode_filtreg2(unsigned int data); 12 | void mmcm_decode_power7(unsigned int data); 13 | void mmcm_decode_reg(unsigned int adr, unsigned int data); 14 | 15 | void hdmi_out0_mmcm_write(int adr, int data); 16 | int hdmi_out0_mmcm_read(int adr); 17 | 18 | #ifdef CSR_HDMI_IN0_CLOCKING_MMCM_DRDY_O_ADDR 19 | void hdmi_in0_clocking_mmcm_write_o(int adr, int data); 20 | int hdmi_in0_clocking_mmcm_read_o(int adr); 21 | void hdmi_in0_clocking_mmcm_write(int adr, int data); 22 | int hdmi_in0_clocking_mmcm_read(int adr); 23 | #endif 24 | 25 | #ifdef CSR_HDMI_IN1_CLOCKING_MMCM_DRDY_O_ADDR 26 | void hdmi_in1_clocking_mmcm_write_o(int adr, int data); 27 | int hdmi_in1_clocking_mmcm_read_o(int adr); 28 | void hdmi_in1_clocking_mmcm_write(int adr, int data); 29 | int hdmi_in1_clocking_mmcm_read(int adr); 30 | #endif 31 | 32 | void mmcm_config_for_clock(int freq); 33 | void mmcm_dump(void); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /litescope/csr.csv: -------------------------------------------------------------------------------- 1 | csr_base,analyzer,0xe0008000,, 2 | csr_base,io,0xe0008800,, 3 | csr_register,analyzer_mux_value,0xe0008000,1,rw 4 | csr_register,analyzer_frontend_trigger_value,0xe0008004,4,rw 5 | csr_register,analyzer_frontend_trigger_mask,0xe0008014,4,rw 6 | csr_register,analyzer_frontend_subsampler_value,0xe0008024,1,rw 7 | csr_register,analyzer_storage_start,0xe0008028,1,rw 8 | csr_register,analyzer_storage_length,0xe000802c,1,rw 9 | csr_register,analyzer_storage_offset,0xe0008030,1,rw 10 | csr_register,analyzer_storage_idle,0xe0008034,1,ro 11 | csr_register,analyzer_storage_wait,0xe0008038,1,ro 12 | csr_register,analyzer_storage_run,0xe000803c,1,ro 13 | csr_register,analyzer_storage_mem_flush,0xe0008040,1,rw 14 | csr_register,analyzer_storage_mem_valid,0xe0008044,1,ro 15 | csr_register,analyzer_storage_mem_ready,0xe0008048,1,rw 16 | csr_register,analyzer_storage_mem_data,0xe000804c,4,ro 17 | csr_register,io_in,0xe0008800,1,ro 18 | csr_register,io_out,0xe0008804,1,rw 19 | constant,nmi_interrupt,0,, 20 | constant,uart_interrupt,2,, 21 | constant,csr_data_width,32,, 22 | constant,system_clock_frequency,100000000,, 23 | constant,config_clock_frequency,100000000,, 24 | constant,config_cpu_reset_addr,0,, 25 | constant,config_cpu_type,NONE,, 26 | constant,config_csr_data_width,32,, 27 | memory_region,sram,0x10000000,4096, 28 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | _ __ _______ _____ ____ _____ 2 | / |/ /_/_ __/ | / /_ |___/ __/__ / ___/ 3 | / / -_) / | |/ / __/___/\ \/ _ \/ /__ 4 | /_/|_/\__/_/ |___/____/ /___/\___/\___/ 5 | 6 | Copyright 2016-2017 / EnjoyDigital 7 | 8 | NeTV2 SoC based on LiteX 9 | 10 | [> Getting started 11 | ------------------ 12 | 1. Install Python3 and your vendor's software 13 | 14 | 2. Obtain LiteX and install it: 15 | git clone https://github.com/enjoy-digital/litex --recursive 16 | cd litex 17 | python3 setup.py develop 18 | cd .. 19 | 20 | 3. Obtain LiteDRAM and install it: 21 | git clone https://github.com/enjoy-digital/litedram 22 | cd litedram 23 | python3 setup.py develop 24 | cd .. 25 | 26 | 4. Obtain LitePCIe and install it: 27 | git clone https://github.com/enjoy-digital/litepcie 28 | cd litepcie 29 | python3 setup.py develop 30 | cd .. 31 | 32 | 5. Obtain LiteVideo and install it: 33 | git clone https://github.com/enjoy-digital/litevideo 34 | cd litedram 35 | python3 setup.py develop 36 | cd .. 37 | 38 | 6. Build the gateware and software: 39 | make netv2_base/netv2_pcie/netv2_video 40 | make load 41 | 42 | [> Status 43 | --------- 44 | 45 | NeTV2: 46 | UART: OK 47 | PCIe: OK (X1) 48 | DDR3: OK 49 | HDMI_OUT: OK (with DVI up to 1080p60) 50 | HDMI_IN: OK (with DVI up to 1080p60) 51 | 52 | NeTV2-MVP: 53 | UART: OK 54 | PCIe: OK (X2) 55 | DDR3: OK 56 | HDMI_OUT_0: OK 57 | HDMI_IN_0: OK (with DVI up to 1080p60) 58 | HDMI_OUT_1: OK 59 | HDMI_IN_1: OK (with DVI up to 1080p60) 60 | 61 | [> Contact 62 | ---------- 63 | E-mail: florent@enjoy-digital.fr -------------------------------------------------------------------------------- /software/pcie/kernel/litepcie.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LitePCIe driver 3 | * 4 | */ 5 | #ifndef _LINUX_LITEPCIE_H 6 | #define _LINUX_LITEPCIE_H 7 | 8 | #include 9 | 10 | struct litepcie_ioctl_mmap_info { 11 | unsigned long reg_offset; 12 | unsigned long reg_size; 13 | 14 | unsigned long dma_tx_buf_offset; 15 | unsigned long dma_tx_buf_size; 16 | unsigned long dma_tx_buf_count; 17 | 18 | unsigned long dma_rx_buf_offset; 19 | unsigned long dma_rx_buf_size; 20 | unsigned long dma_rx_buf_count; 21 | }; 22 | 23 | struct litepcie_ioctl_dma_start { 24 | __u32 dma_flags; /* see LITEPCIE_DMA_FLAGS_x */ 25 | __u32 tx_buf_size; /* in bytes, must be < dma_buf_pitch. 0 means no TX */ 26 | __u32 tx_buf_count; 27 | __u32 rx_buf_size; /* in bytes, must be < dma_buf_pitch. 0 means no RX */ 28 | __u32 rx_buf_count; 29 | }; 30 | 31 | /* if tx_wait is true, wait until the current TX bufffer is 32 | different from tx_buf_num. If tx_wait is false, wait until the 33 | current RX buffer is different from rx_buf_num. Return the last 34 | TX buffer in tx_buf_num and the last RX buffer in 35 | rx_buf_num. */ 36 | struct litepcie_ioctl_dma_wait { 37 | __s32 timeout; /* in ms. Return -EAGAIN if timeout occured without event */ 38 | __u32 tx_wait; 39 | __u32 tx_buf_num; /* read/write */ 40 | __u32 rx_buf_num; /* read/write */ 41 | }; 42 | 43 | #define LITEPCIE_IOCTL 'S' 44 | 45 | #define LITEPCIE_IOCTL_GET_MMAP_INFO _IOR(LITEPCIE_IOCTL, 0, struct litepcie_ioctl_mmap_info) 46 | #define LITEPCIE_IOCTL_DMA_START _IOW(LITEPCIE_IOCTL, 1, struct litepcie_ioctl_dma_start) 47 | #define LITEPCIE_IOCTL_DMA_STOP _IO(LITEPCIE_IOCTL, 2) 48 | #define LITEPCIE_IOCTL_DMA_WAIT _IOWR(LITEPCIE_IOCTL, 3, struct litepcie_ioctl_dma_wait) 49 | 50 | #endif /* _LINUX_LITEPCIE_H */ 51 | -------------------------------------------------------------------------------- /firmware/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "flags.h" 11 | #include 12 | #include 13 | 14 | #include "config.h" 15 | #include "ci.h" 16 | #include "processor.h" 17 | #include "pattern.h" 18 | 19 | 20 | int main(void) 21 | { 22 | irq_setmask(0); 23 | irq_setie(1); 24 | uart_init(); 25 | #ifdef CSR_HDMI_OUT0_I2C_W_ADDR 26 | hdmi_out0_i2c_init(); 27 | #endif 28 | 29 | puts("\nNeTV2 CPU testing software built "__DATE__" "__TIME__); 30 | 31 | config_init(); 32 | time_init(); 33 | 34 | processor_init(); 35 | processor_update(); 36 | processor_start(config_get(CONFIG_KEY_RESOLUTION)); 37 | 38 | ci_prompt(); 39 | 40 | printf( "hdmi_in1_frame_overflow_read %x\n", hdmi_in1_frame_overflow_read() ); 41 | printf( "hdmi_in1_dma_frame_size_read %x\n", hdmi_in1_dma_frame_size_read() ); 42 | printf( "hdmi_in1_dma_slot0_status_read %x\n", hdmi_in1_dma_slot0_status_read() ); 43 | printf( "hdmi_in1_dma_slot0_address_read %x\n", hdmi_in1_dma_slot0_address_read() ); 44 | printf( "hdmi_in1_dma_slot1_status_read %x\n", hdmi_in1_dma_slot1_status_read() ); 45 | printf( "hdmi_in1_dma_slot1_addess_read %x\n", hdmi_in1_dma_slot1_address_read() ); 46 | printf( "hdmi_in1_dma_ev_status_read %x\n", hdmi_in1_dma_ev_status_read() ); 47 | printf( "hdmi_in1_dma_ev_pending_read %x\n", hdmi_in1_dma_ev_pending_read() ); 48 | printf( "hdmi_in1_dma_ev_enable_read %x\n", hdmi_in1_dma_ev_enable_read() ); 49 | 50 | processor_hdmi_out0_source = VIDEO_IN_HDMI_IN1; // this is hard-wired in this scenario 51 | 52 | while(1) { 53 | processor_service(); 54 | ci_service(); 55 | pattern_service(); 56 | } 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /software/pcie/user/litepcie_lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * LitePCIe library 3 | * 4 | */ 5 | #ifndef LITEPCIE_LIB_H 6 | #define LITEPCIE_LIB_H 7 | 8 | #include 9 | #include 10 | 11 | #define LITEPCIE_FILENAME "/dev/litepcie0" 12 | 13 | typedef struct { 14 | int litepcie_fd; 15 | struct litepcie_ioctl_mmap_info mmap_info; 16 | uint8_t *dma_tx_buf; 17 | int dma_tx_buf_size; 18 | uint8_t *dma_rx_buf; 19 | int dma_rx_buf_size; 20 | uint8_t *reg_buf; 21 | 22 | unsigned int tx_buf_size; /* in bytes */ 23 | unsigned int tx_buf_count; /* number of buffers */ 24 | unsigned int rx_buf_size; /* in bytes */ 25 | unsigned int rx_buf_count; /* number of buffers */ 26 | 27 | unsigned int tx_buf_len; /* in samples */ 28 | unsigned int rx_buf_len; /* in samples */ 29 | 30 | pthread_mutex_t fifo_mutex; 31 | int64_t rx_timestamp; /* timestamp (in samples) of the current RX buffer */ 32 | unsigned int rx_buf_index; /* index of the current RX buffer */ 33 | unsigned int rx_buf_next; /* index of the next buffer after the 34 | last received buffer */ 35 | BOOL has_rx_timestamp; /* true if received at least one buffer */ 36 | 37 | int64_t tx_underflow_count; /* TX too late */ 38 | int64_t rx_overflow_count; /* RX too late */ 39 | } LitePCIeState; 40 | 41 | void *litepcie_malloc(int size); 42 | void *litepcie_mallocz(int size); 43 | void litepcie_free(void *ptr); 44 | void __attribute__((format(printf, 2, 3))) litepcie_log(LitePCIeState *s, const char *fmt, ...); 45 | int64_t litepcie_get_time_ms(void); 46 | LitePCIeState *litepcie_open(const char *device_name); 47 | void litepcie_close(LitePCIeState *s); 48 | void litepcie_dma_start(LitePCIeState *s, int buf_size, int buf_count, BOOL is_loopback); 49 | void litepcie_dma_stop(LitePCIeState *s); 50 | void litepcie_writel(LitePCIeState *s, uint32_t addr, uint32_t val); 51 | uint32_t litepcie_readl(LitePCIeState *s, uint32_t addr); 52 | 53 | #endif /* LITEPCIE_LIB_H */ 54 | -------------------------------------------------------------------------------- /firmware/bist.c: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef CSR_GENERATOR_BASE 3 | #include "bist.h" 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "ci.h" 12 | 13 | 14 | #define test_size 128*1024*1024 15 | 16 | unsigned int ticks; 17 | unsigned int speed; 18 | 19 | static void busy_wait(unsigned int ds) 20 | { 21 | timer0_en_write(0); 22 | timer0_reload_write(0); 23 | timer0_load_write(SYSTEM_CLOCK_FREQUENCY/10*ds); 24 | timer0_en_write(1); 25 | timer0_update_value_write(1); 26 | while(timer0_value_read()) timer0_update_value_write(1); 27 | } 28 | 29 | void bist_test(void) { 30 | // empty any characters pending 31 | while(readchar_nonblock() != 0) { 32 | printf( "readchar_nonblock(): %d\n", readchar_nonblock() ); 33 | printf( "emptying buffer: %02x\n", (unsigned int) uart_read() ); 34 | } 35 | while(readchar_nonblock() == 0) { 36 | // write 37 | printf("writing %d Mbytes...", test_size/(1024*1024)); 38 | generator_reset_write(1); 39 | generator_reset_write(0); 40 | generator_base_write(0x20000); 41 | generator_length_write((test_size*8)/128); 42 | 43 | timer0_en_write(0); 44 | timer0_load_write(0xffffffff); 45 | timer0_en_write(1); 46 | 47 | generator_start_write(1); 48 | while(generator_done_read() == 0); 49 | 50 | timer0_update_value_write(1); 51 | ticks = timer0_value_read(); 52 | ticks = 0xffffffff - ticks; 53 | speed = SYSTEM_CLOCK_FREQUENCY/ticks; 54 | speed = test_size*speed/1000000; 55 | speed = 8*speed; 56 | printf(" / %u Mbps\n", speed); 57 | 58 | // read 59 | printf("reading %d Mbytes...", test_size/(1024*1024)); 60 | checker_reset_write(1); 61 | checker_reset_write(0); 62 | checker_base_write(0x20000); 63 | checker_length_write((test_size*8)/128); 64 | 65 | timer0_en_write(0); 66 | timer0_load_write(0xffffffff); 67 | timer0_en_write(1); 68 | 69 | checker_start_write(1); 70 | while(checker_done_read() == 0); 71 | 72 | timer0_update_value_write(1); 73 | ticks = timer0_value_read(); 74 | ticks = 0xffffffff - ticks; 75 | speed = SYSTEM_CLOCK_FREQUENCY/ticks; 76 | speed = test_size*speed/1000000; 77 | speed = 8*speed; 78 | printf(" / %u Mbps\n", speed); 79 | 80 | // errors 81 | printf("errors: %d\n", checker_errors_read()); 82 | 83 | // delay 84 | busy_wait(10); 85 | } 86 | 87 | } 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /firmware/hdmi_out0.c: -------------------------------------------------------------------------------- 1 | #include 2 | #ifdef CSR_HDMI_OUT0_I2C_W_ADDR 3 | #include 4 | #include "i2c.h" 5 | #include "hdmi_out0.h" 6 | 7 | I2C hdmi_out0_i2c; 8 | int hdmi_out0_debug_enabled = 0; 9 | 10 | void hdmi_out0_i2c_init(void) { 11 | hdmi_out0_i2c.w_read = hdmi_out0_i2c_w_read; 12 | hdmi_out0_i2c.w_write = hdmi_out0_i2c_w_write; 13 | hdmi_out0_i2c.r_read = hdmi_out0_i2c_r_read; 14 | i2c_init(&hdmi_out0_i2c); 15 | } 16 | 17 | void hdmi_out0_print_edid(void) { 18 | int eeprom_addr, e, extension_number = 0; 19 | unsigned char b; 20 | unsigned char sum = 0; 21 | 22 | i2c_start_cond(&hdmi_out0_i2c); 23 | b = i2c_write(&hdmi_out0_i2c, 0xa0); 24 | if (!b && hdmi_out0_debug_enabled) 25 | printf("hdmi_out0: NACK while writing slave address!\r\n"); 26 | b = i2c_write(&hdmi_out0_i2c, 0x00); 27 | if (!b && hdmi_out0_debug_enabled) 28 | printf("hdmi_out0: NACK while writing eeprom address!\r\n"); 29 | i2c_start_cond(&hdmi_out0_i2c); 30 | b = i2c_write(&hdmi_out0_i2c, 0xa1); 31 | if (!b && hdmi_out0_debug_enabled) 32 | printf("hdmi_out0: NACK while writing slave address (2)!\r\n"); 33 | for (eeprom_addr = 0 ; eeprom_addr < 128 ; eeprom_addr++) { 34 | b = i2c_read(&hdmi_out0_i2c, eeprom_addr == 127 && extension_number == 0 ? 0 : 1); 35 | sum +=b; 36 | printf("%02X ", b); 37 | if(!((eeprom_addr+1) % 16)) 38 | printf("\r\n"); 39 | if(eeprom_addr == 126) 40 | extension_number = b; 41 | if(eeprom_addr == 127 && sum != 0) 42 | { 43 | printf("Checksum ERROR in EDID block 0\r\n"); 44 | i2c_stop_cond(&hdmi_out0_i2c); 45 | return; 46 | } 47 | } 48 | for(e = 0; e < extension_number; e++) 49 | { 50 | printf("\r\n"); 51 | sum = 0; 52 | for (eeprom_addr = 0 ; eeprom_addr < 128 ; eeprom_addr++) { 53 | b = i2c_read(&hdmi_out0_i2c, eeprom_addr == 127 && e == extension_number - 1 ? 0 : 1); 54 | sum += b; 55 | printf("%02X ", b); 56 | if(!((eeprom_addr+1) % 16)) 57 | printf("\r\n"); 58 | if(eeprom_addr == 127 && sum != 0) 59 | { 60 | printf("Checksum ERROR in EDID extension block %d\r\n", e); 61 | i2c_stop_cond(&hdmi_out0_i2c); 62 | return; 63 | } 64 | } 65 | } 66 | i2c_stop_cond(&hdmi_out0_i2c); 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /litescope/build.py~: -------------------------------------------------------------------------------- 1 | from litex.gen import * 2 | 3 | from litex.build.tools import write_to_file 4 | from litex.build.generic_platform import * 5 | from litex.build.xilinx.platform import XilinxPlatform 6 | 7 | from litex.soc.integration.soc_core import SoCCore 8 | from litex.soc.cores.uart import UARTWishboneBridge 9 | from litex.soc.integration import cpu_interface 10 | 11 | from litescope import LiteScopeAnalyzer, LiteScopeIO 12 | 13 | 14 | _io = [ 15 | ("clock", 0, Pins(1)), 16 | ("reset", 1, Pins(1)), 17 | ("serial", 0, 18 | Subsignal("tx", Pins(1)), 19 | Subsignal("rx", Pins(1)), 20 | ), 21 | ("bus", 0, Pins(128)), 22 | ("i", 0, Pins(16)), 23 | ("o", 0, Pins(16)) 24 | ] 25 | 26 | class CorePlatform(XilinxPlatform): 27 | def __init__(self): 28 | XilinxPlatform.__init__(self, "", _io) 29 | 30 | 31 | class Core(SoCCore): 32 | platform = CorePlatform() 33 | csr_map = { 34 | "analyzer": 16, 35 | "io": 17 36 | } 37 | csr_map.update(SoCCore.csr_map) 38 | 39 | def __init__(self, platform, clk_freq=int(100e6)): 40 | self.clock_domains.cd_sys = ClockDomain("sys") 41 | self.comb += [ 42 | self.cd_sys.clk.eq(platform.request("clock")), 43 | self.cd_sys.rst.eq(platform.request("reset")) 44 | ] 45 | SoCCore.__init__(self, platform, clk_freq, 46 | cpu_type=None, 47 | csr_data_width=32, 48 | with_uart=False, 49 | with_timer=False 50 | ) 51 | self.add_cpu_or_bridge(UARTWishboneBridge(platform.request("serial"), clk_freq)) 52 | self.add_wb_master(self.cpu_or_bridge.wishbone) 53 | self.submodules.analyzer = LiteScopeAnalyzer(platform.request("bus"), 512) 54 | self.submodules.io = LiteScopeIO(16) 55 | self.comb += [ 56 | self.io.input.eq(platform.request("i")), 57 | platform.request("o").eq(self.io.output), 58 | ] 59 | 60 | 61 | # define platform/core 62 | platform = CorePlatform() 63 | core = Core(platform) 64 | 65 | # generate verilog 66 | v_output = platform.get_verilog(core, name="litescope") 67 | v_output.write("litescope.v") 68 | 69 | # generate csr.csv 70 | memory_regions = core.get_memory_regions() 71 | csr_regions = core.get_csr_regions() 72 | constants = core.get_constants() 73 | write_to_file("csr.csv", cpu_interface.get_csr_csv(csr_regions, constants, memory_regions)) 74 | 75 | # generate analyzer.csv 76 | core.analyzer.export_csv(v_output.ns, "analyzer.csv") 77 | -------------------------------------------------------------------------------- /firmware/i2c.c: -------------------------------------------------------------------------------- 1 | #include "asm.h" 2 | #include "i2c.h" 3 | 4 | /* I2C bit banging */ 5 | int i2c_init(I2C *i2c) 6 | { 7 | unsigned int timeout; 8 | 9 | i2c->started = 0; 10 | i2c->w_write(I2C_SCL); 11 | /* Check the I2C bus is ready */ 12 | timeout = 1000; 13 | while((timeout > 0) && (!(i2c->r_read() & I2C_SDAIN))) timeout--; 14 | 15 | return timeout; 16 | } 17 | 18 | void i2c_delay(void) 19 | { 20 | unsigned int i; 21 | 22 | for(i=0;i<1000;i++) NOP; 23 | } 24 | 25 | /* I2C bit-banging functions from http://en.wikipedia.org/wiki/I2c */ 26 | unsigned int i2c_read_bit(I2C *i2c) 27 | { 28 | unsigned int bit; 29 | 30 | /* Let the slave drive data */ 31 | i2c->w_write(0); 32 | i2c_delay(); 33 | i2c->w_write(I2C_SCL); 34 | i2c_delay(); 35 | bit = i2c->r_read() & I2C_SDAIN; 36 | i2c_delay(); 37 | i2c->w_write(0); 38 | return bit; 39 | } 40 | 41 | void i2c_write_bit(I2C *i2c, unsigned int bit) 42 | { 43 | if(bit) { 44 | i2c->w_write(I2C_SDAOE | I2C_SDAOUT); 45 | } else { 46 | i2c->w_write(I2C_SDAOE); 47 | } 48 | i2c_delay(); 49 | /* Clock stretching */ 50 | i2c->w_write(i2c->w_read() | I2C_SCL); 51 | i2c_delay(); 52 | i2c->w_write(i2c->w_read() & ~I2C_SCL); 53 | } 54 | 55 | void i2c_start_cond(I2C *i2c) 56 | { 57 | if(i2c->started) { 58 | /* set SDA to 1 */ 59 | i2c->w_write(I2C_SDAOE | I2C_SDAOUT); 60 | i2c_delay(); 61 | i2c->w_write(i2c->w_read() | I2C_SCL); 62 | i2c_delay(); 63 | } 64 | /* SCL is high, set SDA from 1 to 0 */ 65 | i2c->w_write(I2C_SDAOE|I2C_SCL); 66 | i2c_delay(); 67 | i2c->w_write(I2C_SDAOE); 68 | i2c->started = 1; 69 | } 70 | 71 | void i2c_stop_cond(I2C *i2c) 72 | { 73 | /* set SDA to 0 */ 74 | i2c->w_write(I2C_SDAOE); 75 | i2c_delay(); 76 | /* Clock stretching */ 77 | i2c->w_write(I2C_SDAOE | I2C_SCL); 78 | /* SCL is high, set SDA from 0 to 1 */ 79 | i2c->w_write(I2C_SCL); 80 | i2c_delay(); 81 | i2c->started = 0; 82 | } 83 | 84 | unsigned int i2c_write(I2C *i2c, unsigned char byte) 85 | { 86 | unsigned int bit; 87 | unsigned int ack; 88 | 89 | for(bit = 0; bit < 8; bit++) { 90 | i2c_write_bit(i2c, byte & 0x80); 91 | byte <<= 1; 92 | } 93 | ack = !i2c_read_bit(i2c); 94 | return ack; 95 | } 96 | 97 | unsigned char i2c_read(I2C *i2c, int ack) 98 | { 99 | unsigned char byte = 0; 100 | unsigned int bit; 101 | 102 | for(bit = 0; bit < 8; bit++) { 103 | byte <<= 1; 104 | byte |= i2c_read_bit(i2c); 105 | } 106 | i2c_write_bit(i2c, !ack); 107 | return byte; 108 | } 109 | -------------------------------------------------------------------------------- /litescope/build.py: -------------------------------------------------------------------------------- 1 | from litex.gen import * 2 | 3 | from litex.build.tools import write_to_file 4 | from litex.build.generic_platform import * 5 | from litex.build.xilinx.platform import XilinxPlatform 6 | 7 | from litex.soc.integration.soc_core import SoCCore 8 | from litex.soc.cores.uart import UARTWishboneBridge 9 | from litex.soc.integration import cpu_interface 10 | 11 | from litescope import LiteScopeAnalyzer, LiteScopeIO 12 | 13 | 14 | _io = [ 15 | ("clock", 0, Pins(1)), 16 | ("reset", 1, Pins(1)), 17 | ("serial", 0, 18 | Subsignal("tx", Pins(1)), 19 | Subsignal("rx", Pins(1)), 20 | ), 21 | ("bus", 0, Pins(128)), 22 | ("i", 0, Pins(16)), 23 | ("o", 0, Pins(16)) 24 | ] 25 | 26 | class CorePlatform(XilinxPlatform): 27 | def __init__(self): 28 | XilinxPlatform.__init__(self, "", _io) 29 | 30 | 31 | class Core(SoCCore): 32 | platform = CorePlatform() 33 | csr_map = { 34 | "analyzer": 16, 35 | "io": 17 36 | } 37 | csr_map.update(SoCCore.csr_map) 38 | 39 | def __init__(self, platform, clk_freq=int(100e6)): 40 | self.clock_domains.cd_sys = ClockDomain("sys") 41 | self.comb += [ 42 | self.cd_sys.clk.eq(platform.request("clock")), 43 | self.cd_sys.rst.eq(platform.request("reset")) 44 | ] 45 | SoCCore.__init__(self, platform, clk_freq, 46 | cpu_type=None, 47 | csr_data_width=32, 48 | with_uart=False, 49 | with_timer=False 50 | ) 51 | self.add_cpu_or_bridge(UARTWishboneBridge(platform.request("serial"), clk_freq, baudrate=3000000)) 52 | self.add_wb_master(self.cpu_or_bridge.wishbone) 53 | self.submodules.analyzer = LiteScopeAnalyzer(platform.request("bus"), 512) 54 | self.submodules.io = LiteScopeIO(16) 55 | self.comb += [ 56 | self.io.input.eq(platform.request("i")), 57 | platform.request("o").eq(self.io.output), 58 | ] 59 | 60 | 61 | # define platform/core 62 | platform = CorePlatform() 63 | core = Core(platform) 64 | 65 | # generate verilog 66 | v_output = platform.get_verilog(core, name="litescope") 67 | v_output.write("litescope.v") 68 | 69 | # generate csr.csv 70 | memory_regions = core.get_memory_regions() 71 | csr_regions = core.get_csr_regions() 72 | constants = core.get_constants() 73 | write_to_file("csr.csv", cpu_interface.get_csr_csv(csr_regions, constants, memory_regions)) 74 | 75 | # generate analyzer.csv 76 | core.analyzer.export_csv(v_output.ns, "analyzer.csv") 77 | 78 | """ 79 | assign videooverlaysoc_litescope_bus = { 80 | videooverlaysoc_videooverlaysoc_videooverlaysoc_ibus_sel[3:0], 81 | 1'b0, 82 | videooverlaysoc_videooverlaysoc_videooverlaysoc_ibus_err, 83 | videooverlaysoc_videooverlaysoc_videooverlaysoc_ibus_ack, 84 | videooverlaysoc_videooverlaysoc_videooverlaysoc_ibus_stb, 85 | videooverlaysoc_hdmi_in1_dma_current_address[23:0], 86 | videooverlaysoc_videooverlaysoc_videooverlaysoc_interrupt[31:0], 87 | videooverlaysoc_videooverlaysoc_videooverlaysoc_ibus_dat_r[31:0], 88 | videooverlaysoc_videooverlaysoc_videooverlaysoc_i_adr_o[31:0] }; 89 | """ 90 | -------------------------------------------------------------------------------- /firmware/dump.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "stdio_wrap.h" 7 | 8 | #include 9 | #include 10 | 11 | #include "dump.h" 12 | 13 | /* General address space functions */ 14 | 15 | #define NUMBER_OF_BYTES_ON_A_LINE 16 16 | static void dump_bytes(unsigned int *ptr, int count, unsigned addr) 17 | { 18 | char *data = (char *)ptr; 19 | int line_bytes = 0, i = 0; 20 | 21 | putsnonl("Memory dump:"); 22 | while(count > 0){ 23 | line_bytes = 24 | (count > NUMBER_OF_BYTES_ON_A_LINE)? 25 | NUMBER_OF_BYTES_ON_A_LINE : count; 26 | 27 | wprintf("\n0x%08x ", addr); 28 | for(i=0;i 0x7e)) 38 | wprintf("."); 39 | else 40 | wprintf("%c", *(data+i)); 41 | } 42 | 43 | for(;i [length]\n"); 61 | return; 62 | } 63 | addr = (unsigned *)strtoul(startaddr, &c, 0); 64 | if(*c != 0) { 65 | wprintf("incorrect address\n"); 66 | return; 67 | } 68 | if(*len == 0) { 69 | length = 4; 70 | } else { 71 | length = strtoul(len, &c, 0); 72 | if(*c != 0) { 73 | wprintf("incorrect length\n"); 74 | return; 75 | } 76 | } 77 | 78 | dump_bytes(addr, length, (unsigned)addr); 79 | } 80 | 81 | void mw(char *addr, char *value, char *count) 82 | { 83 | char *c; 84 | unsigned int *addr2; 85 | unsigned int value2; 86 | unsigned int count2; 87 | unsigned int i; 88 | 89 | if((*addr == 0) || (*value == 0)) { 90 | wprintf("mw
[count]\n"); 91 | return; 92 | } 93 | addr2 = (unsigned int *)strtoul(addr, &c, 0); 94 | if(*c != 0) { 95 | wprintf("incorrect address\n"); 96 | return; 97 | } 98 | value2 = strtoul(value, &c, 0); 99 | if(*c != 0) { 100 | wprintf("incorrect value\n"); 101 | return; 102 | } 103 | if(*count == 0) { 104 | count2 = 1; 105 | } else { 106 | count2 = strtoul(count, &c, 0); 107 | if(*c != 0) { 108 | wprintf("incorrect count\n"); 109 | return; 110 | } 111 | } 112 | for (i=0;i [count]\n"); 125 | return; 126 | } 127 | dstaddr2 = (unsigned int *)strtoul(dstaddr, &c, 0); 128 | if(*c != 0) { 129 | wprintf("incorrect destination address\n"); 130 | return; 131 | } 132 | srcaddr2 = (unsigned int *)strtoul(srcaddr, &c, 0); 133 | if(*c != 0) { 134 | wprintf("incorrect source address\n"); 135 | return; 136 | } 137 | if(*count == 0) { 138 | count2 = 1; 139 | } else { 140 | count2 = strtoul(count, &c, 0); 141 | if(*c != 0) { 142 | wprintf("incorrect count\n"); 143 | return; 144 | } 145 | } 146 | for (i=0;i 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "litepcie.h" 17 | #include "cutils.h" 18 | #include "config.h" 19 | #include "csr.h" 20 | #include "flags.h" 21 | 22 | #include "litepcie_lib.h" 23 | 24 | /* 25 | TODO: 26 | - DMA overflow/underflow detection 27 | */ 28 | 29 | void *litepcie_malloc(int size) 30 | { 31 | return malloc(size); 32 | } 33 | 34 | void *litepcie_mallocz(int size) 35 | { 36 | void *ptr; 37 | ptr = litepcie_malloc(size); 38 | if (!ptr) 39 | return NULL; 40 | memset(ptr, 0, size); 41 | return ptr; 42 | } 43 | 44 | void litepcie_free(void *ptr) 45 | { 46 | free(ptr); 47 | } 48 | 49 | void __attribute__((format(printf, 2, 3))) litepcie_log(LitePCIeState *s, const char *fmt, ...) 50 | { 51 | va_list ap; 52 | 53 | va_start(ap, fmt); 54 | vfprintf(stderr, fmt, ap); 55 | va_end(ap); 56 | } 57 | 58 | /* in ms */ 59 | int64_t litepcie_get_time_ms(void) 60 | { 61 | struct timespec ts; 62 | clock_gettime(CLOCK_MONOTONIC, &ts); 63 | return (int64_t)ts.tv_sec * 1000 + (ts.tv_nsec / 1000000U); 64 | } 65 | 66 | LitePCIeState *litepcie_open(const char *device_name) 67 | { 68 | LitePCIeState *s; 69 | 70 | s = litepcie_mallocz(sizeof(LitePCIeState)); 71 | if (!s) 72 | return NULL; 73 | 74 | s->litepcie_fd = open(device_name, O_RDWR); 75 | if (s->litepcie_fd < 0) { 76 | perror(device_name); 77 | goto fail; 78 | } 79 | 80 | /* map the DMA buffers */ 81 | if (ioctl(s->litepcie_fd, LITEPCIE_IOCTL_GET_MMAP_INFO, &s->mmap_info) != 0) { 82 | perror("LITEPCIE_IOCTL_GET_MMAP_INFO"); 83 | exit(1); 84 | } 85 | 86 | s->dma_tx_buf = mmap(NULL, s->mmap_info.dma_tx_buf_size * 87 | s->mmap_info.dma_tx_buf_count, 88 | PROT_READ | PROT_WRITE, MAP_SHARED, s->litepcie_fd, 89 | s->mmap_info.dma_tx_buf_offset); 90 | if (s->dma_tx_buf == MAP_FAILED) { 91 | perror("mmap1"); 92 | exit(1); 93 | } 94 | 95 | s->dma_rx_buf = mmap(NULL, s->mmap_info.dma_rx_buf_size * 96 | s->mmap_info.dma_rx_buf_count, 97 | PROT_READ | PROT_WRITE, MAP_SHARED, s->litepcie_fd, 98 | s->mmap_info.dma_rx_buf_offset); 99 | if (s->dma_rx_buf == MAP_FAILED) { 100 | perror("mmap2"); 101 | exit(1); 102 | } 103 | 104 | /* map the registers */ 105 | s->reg_buf = mmap(NULL, s->mmap_info.reg_size, 106 | PROT_READ | PROT_WRITE, MAP_SHARED, s->litepcie_fd, 107 | s->mmap_info.reg_offset); 108 | if (s->reg_buf == MAP_FAILED) { 109 | perror("mmap2"); 110 | exit(1); 111 | } 112 | 113 | s->dma_tx_buf_size = s->mmap_info.dma_tx_buf_size; 114 | s->dma_rx_buf_size = s->mmap_info.dma_rx_buf_size; 115 | 116 | pthread_mutex_init(&s->fifo_mutex, NULL); 117 | 118 | return s; 119 | fail: 120 | litepcie_close(s); 121 | return NULL; 122 | } 123 | 124 | void litepcie_dma_start(LitePCIeState *s, int buf_size, int buf_count, BOOL is_loopback) 125 | { 126 | struct litepcie_ioctl_dma_start dma_start; 127 | 128 | if (buf_count > DMA_BUFFER_COUNT) { 129 | litepcie_log(s, "unsupported buf_count\n"); 130 | exit(1); 131 | } 132 | 133 | s->tx_buf_size = s->rx_buf_size = buf_size; 134 | s->tx_buf_count = s->rx_buf_count = buf_count; 135 | 136 | dma_start.dma_flags = 0; 137 | if (is_loopback) 138 | dma_start.dma_flags |= DMA_LOOPBACK_ENABLE; 139 | dma_start.tx_buf_size = s->tx_buf_size; 140 | dma_start.tx_buf_count = s->tx_buf_count; 141 | dma_start.rx_buf_size = s->rx_buf_size; 142 | dma_start.rx_buf_count = s->rx_buf_count; 143 | if (ioctl(s->litepcie_fd, LITEPCIE_IOCTL_DMA_START, &dma_start) < 0) { 144 | perror("LITEPCIE_IOCTL_DMA_START"); 145 | } 146 | } 147 | 148 | void litepcie_dma_stop(LitePCIeState *s) 149 | { 150 | if (ioctl(s->litepcie_fd, LITEPCIE_IOCTL_DMA_STOP, NULL) < 0) { 151 | perror("LITEPCIE_IOCTL_DMA_STOP"); 152 | } 153 | } 154 | 155 | void litepcie_writel(LitePCIeState *s, uint32_t addr, uint32_t val) 156 | { 157 | *(volatile uint32_t *)(s->reg_buf + addr) = val; 158 | } 159 | 160 | uint32_t litepcie_readl(LitePCIeState *s, uint32_t addr) 161 | { 162 | return *(volatile uint32_t *)(s->reg_buf + addr); 163 | } 164 | 165 | void litepcie_close(LitePCIeState *s) 166 | { 167 | pthread_mutex_destroy(&s->fifo_mutex); 168 | 169 | if (s->dma_tx_buf) { 170 | munmap(s->dma_tx_buf, s->mmap_info.dma_tx_buf_size * 171 | s->mmap_info.dma_tx_buf_count); 172 | } 173 | if (s->dma_rx_buf) { 174 | munmap(s->dma_rx_buf, s->mmap_info.dma_rx_buf_size * 175 | s->mmap_info.dma_rx_buf_count); 176 | } 177 | if (s->reg_buf) 178 | munmap(s->reg_buf, s->mmap_info.reg_size); 179 | if (s->litepcie_fd >= 0) 180 | close(s->litepcie_fd); 181 | litepcie_free(s); 182 | } 183 | -------------------------------------------------------------------------------- /gateware/dma.py: -------------------------------------------------------------------------------- 1 | from migen import * 2 | from migen.genlib.cdc import MultiReg, PulseSynchronizer 3 | 4 | from litex.soc.interconnect import stream 5 | from litex.soc.interconnect.csr import * 6 | 7 | from litedram.frontend.dma import LiteDRAMDMAWriter, LiteDRAMDMAReader 8 | 9 | 10 | class DMA(Module): 11 | def __init__(self, mode, dram_port, fifo_depth): 12 | assert mode == dram_port.mode 13 | ashift = log2_int(dram_port.dw//8) 14 | awidth = dram_port.aw + ashift 15 | self.cd = dram_port.cd 16 | 17 | # control 18 | self.enable = Signal(reset=1) # reset to 1 if not used 19 | self.start = Signal(reset=1) # i / reset to 1 if not used 20 | self.idle = Signal() # o 21 | self.slot = Signal() # o 22 | 23 | # parameters 24 | self.slot0_base = Signal(awidth) # in bytes 25 | self.slot1_base = Signal(awidth) # in bytes 26 | self.length = Signal(awidth) # in bytes 27 | 28 | # stream 29 | self.endpoint = endpoint = stream.Endpoint([("data", dram_port.dw)]) 30 | 31 | # # # 32 | 33 | base = Signal(dram_port.aw) 34 | length = Signal(dram_port.aw) 35 | offset = Signal(dram_port.aw) 36 | 37 | # slot selection 38 | self.comb += \ 39 | If(self.slot, 40 | base.eq(self.slot1_base[ashift:]) 41 | ).Else( 42 | base.eq(self.slot0_base[ashift:])) 43 | 44 | # length 45 | self.comb += length.eq(self.length[ashift:]) 46 | 47 | # dma 48 | if mode == "write": 49 | # dma 50 | self.submodules.dma = dma = ResetInserter()(LiteDRAMDMAWriter(dram_port, fifo_depth, True)) 51 | # data 52 | self.comb += dma.sink.data.eq(endpoint.data) 53 | elif mode == "read": 54 | # dma 55 | self.submodules.dma = dma = ResetInserter()(LiteDRAMDMAReader(dram_port, fifo_depth, True)) 56 | # data 57 | self.comb += [ 58 | endpoint.valid.eq(dma.source.valid), 59 | dma.source.ready.eq(endpoint.ready), 60 | endpoint.data.eq(dma.source.data) 61 | ] 62 | 63 | # control 64 | self.submodules.fsm = fsm = FSM(reset_state="IDLE") 65 | fsm.act("IDLE", 66 | self.idle.eq(1), 67 | If(self.enable & self.start, 68 | NextValue(offset, 0), 69 | NextState("RUN") 70 | ) 71 | ) 72 | fsm.act("RUN", 73 | If(mode == "write", 74 | dma.sink.valid.eq(endpoint.valid), 75 | endpoint.ready.eq(dma.sink.ready), 76 | ).Elif(mode == "read", 77 | dma.sink.valid.eq(1), 78 | ), 79 | If(~self.enable, 80 | dma.reset.eq(1), 81 | dram_port.flush.eq(1), 82 | NextState("IDLE") 83 | ).Elif(dma.sink.valid & dma.sink.ready, 84 | NextValue(offset, offset + 1), 85 | If(offset == (length - 1), 86 | NextValue(offset, 0), 87 | NextValue(self.slot, ~self.slot) 88 | ) 89 | ) 90 | ) 91 | self.comb += dma.sink.address.eq(base + offset) 92 | 93 | 94 | class DMAWriter(DMA): 95 | def __init__(self, dram_port, dw=32, fifo_depth=512): 96 | self.sink = stream.Endpoint([("data", dw)]) 97 | 98 | # # # 99 | 100 | DMA.__init__(self, "write", dram_port, fifo_depth) 101 | converter = stream.Converter(dw, dram_port.dw, reverse=False) 102 | self.submodules += converter 103 | self.comb += [ 104 | self.sink.connect(converter.sink), 105 | converter.source.connect(self.endpoint) 106 | ] 107 | 108 | 109 | class DMAReader(DMA): 110 | def __init__(self, dram_port, dw=32, fifo_depth=512): 111 | self.source = stream.Endpoint([("data", dw)]) 112 | 113 | # # # 114 | 115 | DMA.__init__(self, "read", dram_port, fifo_depth) 116 | converter = stream.Converter(dram_port.dw, dw, reverse=False) 117 | self.submodules += converter 118 | self.comb += [ 119 | self.endpoint.connect(converter.sink), 120 | converter.source.connect(self.source) 121 | ] 122 | 123 | 124 | class DMAControl(DMA, AutoCSR): 125 | def __init__(self, dma): 126 | self.enable = CSRStorage() 127 | self.slot0_base = CSRStorage(32) 128 | self.slot1_base = CSRStorage(32) 129 | self.length = CSRStorage(32) 130 | 131 | self.start = CSR() 132 | self.idle = CSRStatus() 133 | self.slot = CSRStatus() 134 | 135 | # # # 136 | 137 | self.specials += [ 138 | MultiReg(self.enable.storage, dma.enable, dma.cd), 139 | MultiReg(self.slot0_base.storage, dma.slot0_base, dma.cd), 140 | MultiReg(self.slot1_base.storage, dma.slot1_base, dma.cd), 141 | MultiReg(self.length.storage, dma.length, dma.cd), 142 | 143 | MultiReg(dma.idle, self.idle.status), 144 | MultiReg(dma.slot, self.slot.status), 145 | ] 146 | 147 | start_sync = PulseSynchronizer("sys", dma.cd) 148 | self.submodules += start_sync 149 | self.comb += [ 150 | start_sync.i.eq(self.start.re), 151 | dma.start.eq(start_sync.o) 152 | ] 153 | 154 | if hasattr(dma, "source"): 155 | self.underflows = CSRStatus(32) 156 | self.sync.pix += [ 157 | If(~dma.source.valid, self.underflows.status.eq(self.underflows.status + 1)) 158 | ] 159 | if hasattr(dma, "sink"): 160 | self.overflows = CSRStatus(32) 161 | self.sync.pix += [ 162 | If(~dma.sink.ready, self.overflows.status.eq(self.overflows.status + 1)) 163 | ] 164 | -------------------------------------------------------------------------------- /firmware/pattern.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include "flags.h" 7 | #include 8 | #include 9 | 10 | #include "pattern.h" 11 | #include "processor.h" 12 | 13 | #define PATTERN_FRAMEBUFFER_BASE 0x08000000 + 0x100000 14 | 15 | unsigned int pattern_framebuffer_base(void) { 16 | return PATTERN_FRAMEBUFFER_BASE; 17 | } 18 | 19 | static const unsigned int color_bar[8] = { 20 | YCBCR422_WHITE, 21 | YCBCR422_YELLOW, 22 | YCBCR422_CYAN, 23 | YCBCR422_GREEN, 24 | YCBCR422_PURPLE, 25 | YCBCR422_RED, 26 | YCBCR422_BLUE, 27 | YCBCR422_BLACK 28 | }; 29 | 30 | static const unsigned char font5x7[] = { 31 | 0x00, 0x00, 0x00, 0x00, 0x00,// (space) 32 | 0x00, 0x00, 0x5F, 0x00, 0x00,// ! 33 | 0x00, 0x07, 0x00, 0x07, 0x00,// " 34 | 0x14, 0x7F, 0x14, 0x7F, 0x14,// # 35 | 0x24, 0x2A, 0x7F, 0x2A, 0x12,// $ 36 | 0x23, 0x13, 0x08, 0x64, 0x62,// % 37 | 0x36, 0x49, 0x55, 0x22, 0x50,// & 38 | 0x00, 0x05, 0x03, 0x00, 0x00,// ' 39 | 0x00, 0x1C, 0x22, 0x41, 0x00,// ( 40 | 0x00, 0x41, 0x22, 0x1C, 0x00,// ) 41 | 0x08, 0x2A, 0x1C, 0x2A, 0x08,// * 42 | 0x08, 0x08, 0x3E, 0x08, 0x08,// + 43 | 0x00, 0x50, 0x30, 0x00, 0x00,// , 44 | 0x08, 0x08, 0x08, 0x08, 0x08,// - 45 | 0x00, 0x60, 0x60, 0x00, 0x00,// . 46 | 0x20, 0x10, 0x08, 0x04, 0x02,// / 47 | 0x3E, 0x51, 0x49, 0x45, 0x3E,// 0 48 | 0x00, 0x42, 0x7F, 0x40, 0x00,// 1 49 | 0x42, 0x61, 0x51, 0x49, 0x46,// 2 50 | 0x21, 0x41, 0x45, 0x4B, 0x31,// 3 51 | 0x18, 0x14, 0x12, 0x7F, 0x10,// 4 52 | 0x27, 0x45, 0x45, 0x45, 0x39,// 5 53 | 0x3C, 0x4A, 0x49, 0x49, 0x30,// 6 54 | 0x01, 0x71, 0x09, 0x05, 0x03,// 7 55 | 0x36, 0x49, 0x49, 0x49, 0x36,// 8 56 | 0x06, 0x49, 0x49, 0x29, 0x1E,// 9 57 | 0x00, 0x36, 0x36, 0x00, 0x00,// : 58 | 0x00, 0x56, 0x36, 0x00, 0x00,// ; 59 | 0x00, 0x08, 0x14, 0x22, 0x41,// < 60 | 0x14, 0x14, 0x14, 0x14, 0x14,// = 61 | 0x41, 0x22, 0x14, 0x08, 0x00,// > 62 | 0x02, 0x01, 0x51, 0x09, 0x06,// ? 63 | 0x32, 0x49, 0x79, 0x41, 0x3E,// @ 64 | 0x7E, 0x11, 0x11, 0x11, 0x7E,// A 65 | 0x7F, 0x49, 0x49, 0x49, 0x36,// B 66 | 0x3E, 0x41, 0x41, 0x41, 0x22,// C 67 | 0x7F, 0x41, 0x41, 0x22, 0x1C,// D 68 | 0x7F, 0x49, 0x49, 0x49, 0x41,// E 69 | 0x7F, 0x09, 0x09, 0x01, 0x01,// F 70 | 0x3E, 0x41, 0x41, 0x51, 0x32,// G 71 | 0x7F, 0x08, 0x08, 0x08, 0x7F,// H 72 | 0x00, 0x41, 0x7F, 0x41, 0x00,// I 73 | 0x20, 0x40, 0x41, 0x3F, 0x01,// J 74 | 0x7F, 0x08, 0x14, 0x22, 0x41,// K 75 | 0x7F, 0x40, 0x40, 0x40, 0x40,// L 76 | 0x7F, 0x02, 0x04, 0x02, 0x7F,// M 77 | 0x7F, 0x04, 0x08, 0x10, 0x7F,// N 78 | 0x3E, 0x41, 0x41, 0x41, 0x3E,// O 79 | 0x7F, 0x09, 0x09, 0x09, 0x06,// P 80 | 0x3E, 0x41, 0x51, 0x21, 0x5E,// Q 81 | 0x7F, 0x09, 0x19, 0x29, 0x46,// R 82 | 0x46, 0x49, 0x49, 0x49, 0x31,// S 83 | 0x01, 0x01, 0x7F, 0x01, 0x01,// T 84 | 0x3F, 0x40, 0x40, 0x40, 0x3F,// U 85 | 0x1F, 0x20, 0x40, 0x20, 0x1F,// V 86 | 0x7F, 0x20, 0x18, 0x20, 0x7F,// W 87 | 0x63, 0x14, 0x08, 0x14, 0x63,// X 88 | 0x03, 0x04, 0x78, 0x04, 0x03,// Y 89 | 0x61, 0x51, 0x49, 0x45, 0x43,// Z 90 | 0x00, 0x00, 0x7F, 0x41, 0x41,// [ 91 | 0x02, 0x04, 0x08, 0x10, 0x20,// "\" 92 | 0x41, 0x41, 0x7F, 0x00, 0x00,// ] 93 | 0x04, 0x02, 0x01, 0x02, 0x04,// ^ 94 | 0x40, 0x40, 0x40, 0x40, 0x40,// _ 95 | 0x00, 0x01, 0x02, 0x04, 0x00,// ` 96 | 0x20, 0x54, 0x54, 0x54, 0x78,// a 97 | 0x7F, 0x48, 0x44, 0x44, 0x38,// b 98 | 0x38, 0x44, 0x44, 0x44, 0x20,// c 99 | 0x38, 0x44, 0x44, 0x48, 0x7F,// d 100 | 0x38, 0x54, 0x54, 0x54, 0x18,// e 101 | 0x08, 0x7E, 0x09, 0x01, 0x02,// f 102 | 0x08, 0x14, 0x54, 0x54, 0x3C,// g 103 | 0x7F, 0x08, 0x04, 0x04, 0x78,// h 104 | 0x00, 0x44, 0x7D, 0x40, 0x00,// i 105 | 0x20, 0x40, 0x44, 0x3D, 0x00,// j 106 | 0x00, 0x7F, 0x10, 0x28, 0x44,// k 107 | 0x00, 0x41, 0x7F, 0x40, 0x00,// l 108 | 0x7C, 0x04, 0x18, 0x04, 0x78,// m 109 | 0x7C, 0x08, 0x04, 0x04, 0x78,// n 110 | 0x38, 0x44, 0x44, 0x44, 0x38,// o 111 | 0x7C, 0x14, 0x14, 0x14, 0x08,// p 112 | 0x08, 0x14, 0x14, 0x18, 0x7C,// q 113 | 0x7C, 0x08, 0x04, 0x04, 0x08,// r 114 | 0x48, 0x54, 0x54, 0x54, 0x20,// s 115 | 0x04, 0x3F, 0x44, 0x40, 0x20,// t 116 | 0x3C, 0x40, 0x40, 0x20, 0x7C,// u 117 | 0x1C, 0x20, 0x40, 0x20, 0x1C,// v 118 | 0x3C, 0x40, 0x30, 0x40, 0x3C,// w 119 | 0x44, 0x28, 0x10, 0x28, 0x44,// x 120 | 0x0C, 0x50, 0x50, 0x50, 0x3C,// y 121 | 0x44, 0x64, 0x54, 0x4C, 0x44,// z 122 | 0x00, 0x08, 0x36, 0x41, 0x00,// { 123 | 0x00, 0x00, 0x7F, 0x00, 0x00,// | 124 | 0x00, 0x41, 0x36, 0x08, 0x00,// } 125 | 0x08, 0x08, 0x2A, 0x1C, 0x08,// -> 126 | 0x08, 0x1C, 0x2A, 0x08, 0x08 // <- 127 | }; 128 | 129 | static int inc_color(int color) { 130 | color++; 131 | return color%8; 132 | } 133 | 134 | static void pattern_draw_text(int x, int y, char *ptr) { 135 | int i, j, k; 136 | int adr; 137 | volatile unsigned int *framebuffer = (unsigned int *)(MAIN_RAM_BASE + PATTERN_FRAMEBUFFER_BASE); 138 | for(i=0; ptr[i] != '\0'; i++) { 139 | for(j=0; j<7; j++) { 140 | for(k=0; k<5; k++) { 141 | adr = 5*(x + i) + k + (2*8*y + 2*j)*processor_h_active/2; 142 | if((font5x7[5*(ptr[i] - ' ') + k] >> j) & 0x1) { 143 | framebuffer[adr + 0*processor_h_active/2] = YCBCR422_BLACK; 144 | framebuffer[adr + 1*processor_h_active/2] = YCBCR422_BLACK; 145 | } 146 | else { 147 | framebuffer[adr + 0*processor_h_active/2] = YCBCR422_WHITE; 148 | framebuffer[adr + 1*processor_h_active/2] = YCBCR422_WHITE; 149 | } 150 | } 151 | } 152 | } 153 | } 154 | 155 | void pattern_fill_framebuffer(int h_active, int m_active) 156 | { 157 | int i; 158 | int color; 159 | flush_l2_cache(); 160 | color = -1; 161 | volatile unsigned int *framebuffer = (unsigned int *)(MAIN_RAM_BASE + PATTERN_FRAMEBUFFER_BASE); 162 | if (pattern == COLOR_BAR_PATTERN) { 163 | /* color bar pattern */ 164 | for(i=0; i= 0) 168 | framebuffer[i] = color_bar[color]; 169 | } 170 | } else if (pattern == BLACK_WHITE_BAR_PATTERN) { 171 | /* vertical black white lines */ 172 | for(i=0; i 2 | #include 3 | #ifdef ENCODER_BASE 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "processor.h" 10 | #include "encoder.h" 11 | 12 | void encoder_write_reg(unsigned int adr, unsigned int value) { 13 | MMPTR(ENCODER_BASE+adr) = value; 14 | } 15 | 16 | unsigned int encoder_read_reg(unsigned int adr) { 17 | return MMPTR(ENCODER_BASE+adr); 18 | } 19 | 20 | const char luma_rom_100[64] = { 21 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 22 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 23 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 24 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 25 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 26 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 27 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 28 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 29 | }; 30 | 31 | const char luma_rom_85[64] = { 32 | 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 33 | 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C, 34 | 0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B, 0x0B, 35 | 0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F, 36 | 0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14, 37 | 0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 38 | 0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22, 39 | 0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E 40 | }; 41 | 42 | const char luma_rom_75[64] = { 43 | 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, 44 | 0x07, 0x07, 0x09, 0x09, 0x08, 0x0A, 0x0C, 0x14, 45 | 0x0D, 0x0C, 0x0B, 0x0B, 0x0C, 0x19, 0x12, 0x13, 46 | 0x0F, 0x14, 0x1D, 0x1A, 0x1F, 0x1E, 0x1D, 0x1A, 47 | 0x1C, 0x1C, 0x20, 0x24, 0x2E, 0x27, 0x20, 0x22, 48 | 0x2C, 0x23, 0x1C, 0x1C, 0x28, 0x37, 0x29, 0x2C, 49 | 0x30, 0x31, 0x34, 0x34, 0x34, 0x1F, 0x27, 0x39, 50 | 0x3D, 0x38, 0x32, 0x3C, 0x2E, 0x33, 0x34, 0x32 51 | }; 52 | 53 | const char luma_rom_50[64] = { 54 | 0x10, 0x0B, 0x0C, 0x0E, 0x0C, 0x0A, 0x10, 0x0E, 55 | 0x0D, 0x0E, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 56 | 0x1A, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, 57 | 0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33, 58 | 0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44, 59 | 0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57, 60 | 0x5F, 0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71, 61 | 0x79, 0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63 62 | }; 63 | 64 | const char chroma_rom_100[64] = { 65 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 66 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 67 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 68 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 69 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 70 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 71 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 72 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 73 | }; 74 | 75 | const char chroma_rom_85[64] = { 76 | 0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, 77 | 0x07, 0x07, 0x09, 0x09, 0x08, 0x0A, 0x0C, 0x14, 78 | 0x0D, 0x0C, 0x0B, 0x0B, 0x0C, 0x19, 0x12, 0x13, 79 | 0x0F, 0x14, 0x1D, 0x1A, 0x1F, 0x1E, 0x1D, 0x1A, 80 | 0x1C, 0x1C, 0x20, 0x24, 0x2E, 0x27, 0x20, 0x22, 81 | 0x2C, 0x23, 0x1C, 0x1C, 0x28, 0x37, 0x29, 0x2C, 82 | 0x30, 0x31, 0x34, 0x34, 0x34, 0x1F, 0x27, 0x39, 83 | 0x3D, 0x38, 0x32, 0x3C, 0x2E, 0x33, 0x34, 0x32 84 | }; 85 | 86 | const char chroma_rom_75[64] = { 87 | 0x09, 0x09, 0x09, 0x0C, 0x0B, 0x0C, 0x18, 0x0D, 88 | 0x0D, 0x18, 0x32, 0x21, 0x1C, 0x21, 0x32, 0x32, 89 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 90 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 91 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 92 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 93 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 94 | 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32 95 | }; 96 | 97 | const char chroma_rom_50[64] = { 98 | 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2F, 0x1A, 99 | 0x1A, 0x2F, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, 100 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 101 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 102 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 103 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 104 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 105 | 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 106 | }; 107 | 108 | static void encoder_config_table(unsigned int base, const char *table) 109 | { 110 | int i; 111 | for(i=0; i<64; i++) 112 | encoder_write_reg(base+4*i, table[i]); 113 | } 114 | 115 | void encoder_init(int quality) { 116 | if(quality == 100) { 117 | encoder_config_table(ENCODER_QUANTIZER_RAM_LUMA_BASE, luma_rom_100); 118 | encoder_config_table(ENCODER_QUANTIZER_RAM_CHROMA_BASE, chroma_rom_100); 119 | encoder_quality = 100; 120 | } else if (quality == 85) { 121 | encoder_config_table(ENCODER_QUANTIZER_RAM_LUMA_BASE, luma_rom_85); 122 | encoder_config_table(ENCODER_QUANTIZER_RAM_CHROMA_BASE, chroma_rom_85); 123 | encoder_quality = 85; 124 | } else if (quality == 75) { 125 | encoder_config_table(ENCODER_QUANTIZER_RAM_LUMA_BASE, luma_rom_75); 126 | encoder_config_table(ENCODER_QUANTIZER_RAM_CHROMA_BASE, chroma_rom_75); 127 | encoder_quality = 75; 128 | } else { 129 | encoder_config_table(ENCODER_QUANTIZER_RAM_LUMA_BASE, luma_rom_50); 130 | encoder_config_table(ENCODER_QUANTIZER_RAM_CHROMA_BASE, chroma_rom_50); 131 | encoder_quality = 50; 132 | } 133 | } 134 | 135 | void encoder_start(short resx, short resy) { 136 | encoder_write_reg(ENCODER_IMAGE_SIZE_REG, (resx << 16) | resy); 137 | encoder_write_reg(ENCODER_START_REG, 7); /* RGB, SOF */ 138 | } 139 | 140 | int encoder_done(void) { 141 | return (encoder_read_reg(ENCODER_STS_REG) & 0x1) == 0; 142 | } 143 | 144 | void encoder_enable(char enable) { 145 | encoder_enabled = enable; 146 | } 147 | 148 | int encoder_set_quality(int quality) { 149 | switch(quality) { 150 | case 100: 151 | case 85: 152 | case 75: 153 | case 50: 154 | encoder_quality = quality; 155 | break; 156 | default: 157 | printf("Unsupported encoder quality (50, 75, 85 or 100)\r\n"); 158 | return 0; 159 | } 160 | return 1; 161 | } 162 | 163 | int encoder_set_fps(int fps) { 164 | if(encoder_target_fps > 0 && encoder_target_fps <= 60) { 165 | encoder_target_fps = fps; 166 | return 0; 167 | } 168 | else { 169 | encoder_target_fps = 30; 170 | return 1; 171 | } 172 | } 173 | 174 | void encoder_service(void) { 175 | 176 | static int last_event; 177 | static int last_fps_event; 178 | static int frame_cnt; 179 | static int can_start; 180 | 181 | if(encoder_enabled) { 182 | if(elapsed(&last_event, SYSTEM_CLOCK_FREQUENCY/encoder_target_fps)) 183 | can_start = 1; 184 | if(can_start & encoder_done()) { 185 | encoder_init(encoder_quality); 186 | encoder_start(processor_h_active, processor_v_active); 187 | can_start = 0; 188 | frame_cnt++; 189 | } 190 | if(encoder_reader_done_read()) { 191 | encoder_reader_h_width_write(processor_h_active); 192 | encoder_reader_v_width_write(processor_v_active); 193 | encoder_reader_start_write(1); 194 | } 195 | if(elapsed(&last_fps_event, SYSTEM_CLOCK_FREQUENCY)) { 196 | encoder_fps = frame_cnt; 197 | frame_cnt = 0; 198 | } 199 | } 200 | } 201 | 202 | #endif 203 | -------------------------------------------------------------------------------- /firmware/edid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "edid.h" 5 | 6 | struct edid { 7 | uint8_t header[8]; 8 | 9 | uint8_t manufacturer[2]; 10 | uint8_t product_code[2]; 11 | uint8_t serial_number[4]; 12 | uint8_t manufacture_week; 13 | uint8_t manufacture_year; 14 | 15 | uint8_t edid_version; 16 | uint8_t edid_revision; 17 | 18 | uint8_t video_input; 19 | uint8_t h_image_size; 20 | uint8_t v_image_size; 21 | uint8_t gamma; 22 | uint8_t feature_support; 23 | 24 | uint8_t cc_rg_l; 25 | uint8_t cc_bw_l; 26 | uint8_t cc_rx_h; 27 | uint8_t cc_ry_h; 28 | uint8_t cc_gx_h; 29 | uint8_t cc_gy_h; 30 | uint8_t cc_bx_h; 31 | uint8_t cc_by_h; 32 | uint8_t cc_wx_h; 33 | uint8_t cc_wy_h; 34 | 35 | uint8_t est_timings_1; 36 | uint8_t est_timings_2; 37 | uint8_t rsv_timings; 38 | 39 | uint8_t timings_std[16]; 40 | 41 | uint8_t data_blocks[4][18]; 42 | 43 | uint8_t ext_block_count; 44 | 45 | uint8_t checksum; 46 | } __attribute__((packed)); 47 | 48 | struct edid_timing { 49 | uint8_t pixel_clock[2]; 50 | 51 | uint8_t h_active_l; 52 | uint8_t h_blanking_l; 53 | uint8_t h_active_blanking_h; 54 | 55 | uint8_t v_active_l; 56 | uint8_t v_blanking_l; 57 | uint8_t v_active_blanking_h; 58 | 59 | uint8_t h_sync_offset_l; 60 | uint8_t h_sync_width_l; 61 | uint8_t v_sync_offset_width_l; 62 | uint8_t hv_sync_offset_width_h; 63 | 64 | uint8_t h_image_size_l; 65 | uint8_t v_image_size_l; 66 | uint8_t hv_image_size_h; 67 | 68 | uint8_t h_border; 69 | uint8_t v_border; 70 | 71 | uint8_t flags; 72 | } __attribute__((packed)); 73 | 74 | struct edid_descriptor { 75 | uint8_t flag0; 76 | uint8_t flag1; 77 | uint8_t flag2; 78 | uint8_t data_type; 79 | uint8_t flag3; 80 | uint8_t data[13]; 81 | } __attribute__((packed)); 82 | 83 | static const char correct_header[8] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}; 84 | 85 | static uint8_t compute_checksum(struct edid *e) 86 | { 87 | uint8_t *p = (uint8_t *)e; 88 | uint8_t sum; 89 | int i; 90 | 91 | sum = 0; 92 | for(i=0;i<127;i++) 93 | sum += p[i]; 94 | return -sum; 95 | } 96 | 97 | int validate_edid(const void *buf) 98 | { 99 | struct edid *e = (struct edid *)buf; 100 | 101 | if(memcmp(e->header, correct_header, 8) != 0) 102 | return 0; 103 | if(compute_checksum(e) != e->checksum) 104 | return 0; 105 | return 1; 106 | } 107 | 108 | void get_monitor_name(const void *buf, char *name) 109 | { 110 | struct edid *e = (struct edid *)buf; 111 | int i; 112 | uint8_t *data_block; 113 | char *c; 114 | 115 | name[0] = 0; 116 | 117 | data_block = NULL; 118 | for(i=0;i<4;i++) 119 | if((e->data_blocks[i][0] == 0x00) 120 | && (e->data_blocks[i][1] == 0x00) 121 | && (e->data_blocks[i][2] == 0x00) 122 | && (e->data_blocks[i][3] == 0xfc)) { 123 | data_block = e->data_blocks[i]; 124 | break; 125 | } 126 | if(!data_block) 127 | return; 128 | 129 | name[MAX_MONITOR_NAME_LEN] = 0; 130 | memcpy(name, &data_block[5], MAX_MONITOR_NAME_LEN); 131 | c = strchr(name, '\n'); 132 | if(c) 133 | *c = 0; 134 | } 135 | 136 | static void generate_edid_timing(uint8_t *data_block, const struct video_timing *timing) 137 | { 138 | struct edid_timing *t = (struct edid_timing *)data_block; 139 | unsigned int h_image_size, v_image_size; 140 | 141 | t->pixel_clock[0] = timing->pixel_clock & 0xff; 142 | t->pixel_clock[1] = timing->pixel_clock >> 8; 143 | 144 | t->h_active_l = timing->h_active & 0xff; 145 | t->h_blanking_l = timing->h_blanking & 0xff; 146 | t->h_active_blanking_h = ((timing->h_active >> 8) << 4) | (timing->h_blanking >> 8); 147 | 148 | t->v_active_l = timing->v_active & 0xff; 149 | t->v_blanking_l = timing->v_blanking & 0xff; 150 | t->v_active_blanking_h = ((timing->v_active >> 8) << 4) | (timing->v_blanking >> 8); 151 | 152 | t->h_sync_offset_l = timing->h_sync_offset & 0xff; 153 | t->h_sync_width_l = timing->h_sync_width & 0xff; 154 | t->v_sync_offset_width_l = timing->v_sync_offset & 0xff; 155 | t->hv_sync_offset_width_h = ((timing->h_sync_offset >> 8) << 6) | ((timing->h_sync_width >> 8) << 4) 156 | | ((timing->v_sync_offset >> 8) << 2) | (timing->v_sync_width >> 8); 157 | 158 | h_image_size = 10*timing->h_active/64; 159 | v_image_size = 10*timing->v_active/64; 160 | t->h_image_size_l = h_image_size & 0xff; 161 | t->v_image_size_l = v_image_size & 0xff; 162 | t->hv_image_size_h = ((h_image_size >> 8) << 4) | (v_image_size >> 8); 163 | 164 | t->h_border = 0; 165 | t->v_border = 0; 166 | 167 | t->flags = 0x1e; 168 | } 169 | 170 | static void generate_monitor_name(uint8_t *data_block, const char *name) 171 | { 172 | struct edid_descriptor *d = (struct edid_descriptor *)data_block; 173 | int i; 174 | 175 | d->flag0 = d->flag1 = d->flag2 = d->flag3 = 0; 176 | d->data_type = 0xfc; 177 | for(i=0;i<12;i++) { 178 | if(!name[i]) 179 | break; 180 | d->data[i] = name[i]; 181 | } 182 | d->data[i++] = 0x0a; 183 | for(;i<13;i++) 184 | d->data[i] = 0x20; 185 | } 186 | 187 | static void generate_unused(uint8_t *data_block) 188 | { 189 | struct edid_descriptor *d = (struct edid_descriptor *)data_block; 190 | 191 | memset(d, 0, sizeof(struct edid_descriptor)); 192 | d->data_type = 0x10; 193 | } 194 | 195 | void generate_edid(void *out, 196 | const char mfg_name[3], const char product_code[2], int year, 197 | const char *name, 198 | const struct video_timing *timing) 199 | { 200 | struct edid *e = (struct edid *)out; 201 | int i, j, k; 202 | 203 | memcpy(e->header, correct_header, 8); 204 | 205 | i = mfg_name[0] - 'A' + 1; 206 | j = mfg_name[1] - 'A' + 1; 207 | k = mfg_name[2] - 'A' + 1; 208 | e->manufacturer[0] = (i << 2) | (j >> 3); 209 | e->manufacturer[1] = ((j & 0x07) << 5) | k; 210 | e->product_code[0] = product_code[0]; e->product_code[1] = product_code[1]; 211 | e->serial_number[0] = e->serial_number[1] = e->serial_number[2] = e->serial_number[3] = 0; 212 | e->manufacture_week = 0; 213 | e->manufacture_year = year - 1990; 214 | 215 | e->edid_version = 1; 216 | e->edid_revision = 3; 217 | 218 | e->video_input = 0x80; /* digital */ 219 | e->h_image_size = timing->h_active/64; 220 | e->v_image_size = timing->v_active/64; 221 | e->gamma = 0x78; 222 | e->feature_support = 0x06; 223 | 224 | e->cc_rg_l = 0; 225 | e->cc_bw_l = 0; 226 | e->cc_rx_h = 0; 227 | e->cc_ry_h = 0; 228 | e->cc_gx_h = 0; 229 | e->cc_gy_h = 0; 230 | e->cc_bx_h = 0; 231 | e->cc_by_h = 0; 232 | e->cc_wx_h = 0; 233 | e->cc_wy_h = 0; 234 | 235 | e->est_timings_1 = timing->established_timing >> 8; 236 | e->est_timings_2 = timing->established_timing & 0xff; 237 | e->rsv_timings = 0; 238 | memset(e->timings_std, 0x01, 16); 239 | 240 | generate_edid_timing(e->data_blocks[0], timing); 241 | generate_monitor_name(e->data_blocks[1], name); 242 | generate_unused(e->data_blocks[2]); 243 | generate_unused(e->data_blocks[3]); 244 | 245 | e->ext_block_count = 0; 246 | 247 | e->checksum = compute_checksum(e); 248 | } 249 | 250 | unsigned calculate_refresh_rate(const struct video_timing* mode) 251 | { 252 | unsigned int refresh_span; 253 | refresh_span = (mode->h_active + mode->h_blanking)*(mode->v_active + mode->v_blanking); 254 | return mode->pixel_clock*10000/refresh_span; 255 | } 256 | -------------------------------------------------------------------------------- /software/pcie/user/litepcie_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LitePCIe utilities 3 | * 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "litepcie.h" 16 | #include "cutils.h" 17 | #include "config.h" 18 | #include "csr.h" 19 | #include "flags.h" 20 | #include "litepcie_lib.h" 21 | 22 | static inline uint32_t seed_to_data(uint32_t seed) 23 | { 24 | #if 1 25 | /* more random but slower */ 26 | return seed * 0x31415976 + 1; 27 | #else 28 | /* simplify debug: just copy the counter */ 29 | return seed; 30 | #endif 31 | } 32 | 33 | static void write_pn_data(uint32_t *dst, int count, uint32_t *pseed) 34 | { 35 | int i; 36 | uint32_t seed; 37 | 38 | seed = *pseed; 39 | for(i = 0; i < count; i++) { 40 | dst[i] = seed_to_data(seed); 41 | seed++; 42 | } 43 | *pseed = seed; 44 | } 45 | 46 | /* Return the number of errors */ 47 | static int check_pn_data(const uint32_t *tab, int count, 48 | uint32_t *pseed) 49 | { 50 | int i, errors; 51 | uint32_t seed; 52 | 53 | errors = 0; 54 | seed = *pseed; 55 | for(i = 0; i < count; i++) { 56 | if (tab[i] != seed_to_data(seed)) { 57 | errors++; 58 | } 59 | seed++; 60 | } 61 | *pseed = seed; 62 | return errors; 63 | } 64 | 65 | #define MAX_SHIFT_OFFSET 128 66 | 67 | /* test DMA with a buffer size of buf_size bytes in loopback 68 | mode. */ 69 | void dma_test(LitePCIeState *s, int buf_size, int buf_count, BOOL is_loopback) 70 | { 71 | int is_first, tx_buf_num, buf_num_cur, buf_num_next; 72 | struct litepcie_ioctl_dma_wait dma_wait; 73 | int buf_stats_count; /* statistics */ 74 | int64_t last_time; 75 | uint32_t tx_seed, rx_seed; 76 | int buf_rx_count, first_rx_buf, rx_errors, shift, d, tx_underflows; 77 | 78 | litepcie_dma_start(s, buf_size, buf_count, is_loopback); 79 | 80 | is_first = 1; 81 | buf_num_cur = 0; /* next buffer to receive */ 82 | /* PN data TX and RX state */ 83 | tx_seed = MAX_SHIFT_OFFSET; 84 | rx_seed = 0; 85 | buf_rx_count = 0; 86 | first_rx_buf = 1; 87 | 88 | /* statistics */ 89 | buf_stats_count = 0; 90 | last_time = litepcie_get_time_ms(); 91 | rx_errors = 0; 92 | shift = 0; 93 | tx_underflows = 0; 94 | 95 | for(;;) { 96 | /* wait until at least one buffer is received */ 97 | dma_wait.timeout = 1000; /* 1 second timeout */ 98 | dma_wait.tx_wait = FALSE; 99 | dma_wait.tx_buf_num = -1; /* not used */ 100 | if (is_first) { 101 | dma_wait.rx_buf_num = -1; /* don't wait, just get the last 102 | received buffer number */ 103 | } else { 104 | dma_wait.rx_buf_num = sub_mod_int(buf_num_cur, 1, buf_count); 105 | } 106 | /* wait until the current buffer number is different from 107 | dma_wait.buf_num */ 108 | if (ioctl(s->litepcie_fd, LITEPCIE_IOCTL_DMA_WAIT, &dma_wait) < 0) { 109 | perror("LITEPCIE_IOCTL_DMA_WAIT"); 110 | } 111 | if (is_first) { 112 | buf_num_cur = dma_wait.rx_buf_num; 113 | is_first = 0; 114 | } 115 | buf_num_next = add_mod_int(dma_wait.rx_buf_num, 1, buf_count); 116 | 117 | while (buf_num_cur != buf_num_next) { 118 | 119 | /* write the TX data 4/10 of a DMA cycle in the future */ 120 | tx_buf_num = add_mod_int(buf_num_cur, 4*buf_count/10, buf_count); 121 | d = sub_mod_int(tx_buf_num, buf_num_next, buf_count); 122 | if (d >= (buf_count / 2)) { 123 | /* we are too late in writing data, which necessarily 124 | gives read errors. */ 125 | tx_underflows++; 126 | } 127 | 128 | write_pn_data((uint32_t *)(s->dma_tx_buf + 129 | tx_buf_num * s->dma_tx_buf_size), 130 | s->tx_buf_size >> 2, &tx_seed); 131 | 132 | if (buf_rx_count >= 4*buf_count/10) { 133 | const uint32_t *rx_buf; 134 | int rx_buf_len; 135 | 136 | rx_buf = (uint32_t *)(s->dma_rx_buf + buf_num_cur * s->dma_rx_buf_size); 137 | rx_buf_len = s->rx_buf_size >> 2; 138 | 139 | if (first_rx_buf) { 140 | uint32_t seed; 141 | 142 | /* find the initial shift */ 143 | for(shift = 0; shift < 2 * MAX_SHIFT_OFFSET; shift++) { 144 | seed = rx_seed + shift; 145 | rx_errors = check_pn_data(rx_buf, rx_buf_len, &seed); 146 | if (rx_errors <= (rx_buf_len / 2)) { 147 | rx_seed = seed; 148 | break; 149 | } 150 | } 151 | if (shift == 2 * MAX_SHIFT_OFFSET) { 152 | printf("Cannot find initial data\n"); 153 | exit(1); 154 | } else { 155 | printf("RX shift = %d\n", 156 | -(shift - MAX_SHIFT_OFFSET)); 157 | } 158 | first_rx_buf = 0; 159 | } else { 160 | /* count the number of errors */ 161 | rx_errors += check_pn_data(rx_buf, rx_buf_len, &rx_seed); 162 | } 163 | } else { 164 | buf_rx_count++; 165 | } 166 | 167 | buf_num_cur = add_mod_int(buf_num_cur, 1, buf_count); 168 | 169 | /* statistics */ 170 | if (++buf_stats_count == 10000) { 171 | int64_t duration; 172 | duration = litepcie_get_time_ms() - last_time; 173 | printf("%0.1f Gb/sec %0.1f bufs/sec tx_underflows=%d errors=%d\n", 174 | (double)buf_stats_count * buf_size * 8 / ((double)duration * 1e6), 175 | (double)buf_stats_count * 1000 / (double)duration, 176 | tx_underflows, rx_errors); 177 | last_time = litepcie_get_time_ms(); 178 | buf_stats_count = 0; 179 | tx_underflows = 0; 180 | rx_errors = 0; 181 | } 182 | } 183 | } 184 | 185 | litepcie_dma_stop(s); 186 | } 187 | 188 | void dma_loopback_test(void) 189 | { 190 | LitePCIeState *s; 191 | 192 | s = litepcie_open(LITEPCIE_FILENAME); 193 | if (!s) { 194 | fprintf(stderr, "Could not init driver\n"); 195 | exit(1); 196 | } 197 | dma_test(s, 16*1024, DMA_BUFFER_COUNT, TRUE); 198 | 199 | litepcie_close(s); 200 | } 201 | 202 | void dump_version(void) 203 | { 204 | LitePCIeState *s; 205 | int i; 206 | unsigned char fpga_identification[256]; 207 | 208 | s = litepcie_open(LITEPCIE_FILENAME); 209 | if (!s) { 210 | fprintf(stderr, "Could not init driver\n"); 211 | exit(1); 212 | } 213 | 214 | for(i=0; i<256; i++) 215 | fpga_identification[i] = litepcie_readl(s, CSR_IDENTIFIER_MEM_BASE + 4*i); 216 | printf("FPGA identification=%s\n", fpga_identification); 217 | 218 | litepcie_close(s); 219 | } 220 | 221 | void help(void) 222 | { 223 | printf("usage: litepcie_util cmd [args...]\n" 224 | "\n" 225 | "available commands:\n" 226 | "dma_loopback_test test DMA loopback operation\n" 227 | "version return fpga version\n" 228 | ); 229 | exit(1); 230 | } 231 | 232 | int main(int argc, char **argv) 233 | { 234 | const char *cmd; 235 | int c; 236 | 237 | for(;;) { 238 | c = getopt(argc, argv, "h"); 239 | if (c == -1) 240 | break; 241 | switch(c) { 242 | case 'h': 243 | help(); 244 | break; 245 | default: 246 | exit(1); 247 | } 248 | } 249 | 250 | if (optind >= argc) 251 | help(); 252 | cmd = argv[optind++]; 253 | 254 | if (!strcmp(cmd, "dma_loopback_test")) { 255 | dma_loopback_test(); 256 | } else if (!strcmp(cmd, "version")) { 257 | dump_version(); 258 | } else { 259 | help(); 260 | } 261 | 262 | return 0; 263 | } 264 | -------------------------------------------------------------------------------- /dma_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import os 4 | 5 | from litex.gen import * 6 | from litex.gen.genlib.resetsync import AsyncResetSynchronizer 7 | 8 | from litex.boards.platforms import arty 9 | 10 | from litex.soc.integration.soc_core import mem_decoder 11 | from litex.soc.integration.soc_sdram import * 12 | from litex.soc.integration.builder import * 13 | from litex.soc.cores import dna, xadc 14 | 15 | from litedram.modules import MT41J128M16 16 | from litedram.phy import a7ddrphy 17 | from litedram.core import ControllerSettings 18 | 19 | from gateware.dma import DMAWriter, DMAReader 20 | 21 | 22 | def csr_map_update(csr_map, csr_peripherals): 23 | csr_map.update(dict((n, v) 24 | for v, n in enumerate(csr_peripherals, start=max(csr_map.values()) + 1))) 25 | 26 | 27 | def period_ns(freq): 28 | return 1e9/freq 29 | 30 | 31 | class CRG(Module): 32 | def __init__(self, platform): 33 | self.clock_domains.cd_sys = ClockDomain() 34 | self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) 35 | self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True) 36 | self.clock_domains.cd_clk200 = ClockDomain() 37 | self.clock_domains.cd_clk50 = ClockDomain() 38 | 39 | clk100 = platform.request("clk100") 40 | rst = ~platform.request("cpu_reset") 41 | 42 | pll_locked = Signal() 43 | pll_fb = Signal() 44 | self.pll_sys = Signal() 45 | pll_sys4x = Signal() 46 | pll_sys4x_dqs = Signal() 47 | pll_clk200 = Signal() 48 | pll_clk50 = Signal() 49 | self.specials += [ 50 | Instance("PLLE2_BASE", 51 | p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, 52 | 53 | # VCO @ 1600 MHz 54 | p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=10.0, 55 | p_CLKFBOUT_MULT=16, p_DIVCLK_DIVIDE=1, 56 | i_CLKIN1=clk100, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, 57 | 58 | # 100 MHz 59 | p_CLKOUT0_DIVIDE=16, p_CLKOUT0_PHASE=0.0, 60 | o_CLKOUT0=self.pll_sys, 61 | 62 | # 400 MHz 63 | p_CLKOUT1_DIVIDE=4, p_CLKOUT1_PHASE=0.0, 64 | o_CLKOUT1=pll_sys4x, 65 | 66 | # 400 MHz dqs 67 | p_CLKOUT2_DIVIDE=4, p_CLKOUT2_PHASE=90.0, 68 | o_CLKOUT2=pll_sys4x_dqs, 69 | 70 | # 200 MHz 71 | p_CLKOUT3_DIVIDE=8, p_CLKOUT3_PHASE=0.0, 72 | o_CLKOUT3=pll_clk200, 73 | 74 | # 50MHz 75 | p_CLKOUT4_DIVIDE=32, p_CLKOUT4_PHASE=0.0, 76 | o_CLKOUT4=pll_clk50 77 | ), 78 | Instance("BUFG", i_I=self.pll_sys, o_O=self.cd_sys.clk), 79 | Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), 80 | Instance("BUFG", i_I=pll_sys4x_dqs, o_O=self.cd_sys4x_dqs.clk), 81 | Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), 82 | Instance("BUFG", i_I=pll_clk50, o_O=self.cd_clk50.clk), 83 | AsyncResetSynchronizer(self.cd_sys, ~pll_locked | rst), 84 | AsyncResetSynchronizer(self.cd_clk200, ~pll_locked | rst), 85 | AsyncResetSynchronizer(self.cd_clk50, ~pll_locked | rst), 86 | ] 87 | 88 | reset_counter = Signal(4, reset=15) 89 | ic_reset = Signal(reset=1) 90 | self.sync.clk200 += \ 91 | If(reset_counter != 0, 92 | reset_counter.eq(reset_counter - 1) 93 | ).Else( 94 | ic_reset.eq(0) 95 | ) 96 | self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset) 97 | 98 | 99 | class BaseSoC(SoCSDRAM): 100 | csr_peripherals = { 101 | "ddrphy", 102 | "dna", 103 | "xadc", 104 | } 105 | csr_map_update(SoCSDRAM.csr_map, csr_peripherals) 106 | 107 | def __init__(self, platform, **kwargs): 108 | clk_freq = int(100e6) 109 | SoCSDRAM.__init__(self, platform, clk_freq, 110 | l2_size=32, 111 | integrated_rom_size=0x8000, 112 | integrated_sram_size=0x8000, 113 | ident="Arty DMA Test SoC", 114 | ident_version=True, 115 | reserve_nmi_interrupt=False, 116 | **kwargs) 117 | 118 | self.submodules.crg = CRG(platform) 119 | self.submodules.dna = dna.DNA() 120 | self.submodules.xadc = xadc.XADC() 121 | 122 | self.crg.cd_sys.clk.attr.add("keep") 123 | self.platform.add_period_constraint(self.crg.cd_sys.clk, period_ns(100e6)) 124 | 125 | # sdram 126 | self.submodules.ddrphy = a7ddrphy.A7DDRPHY(platform.request("ddram")) 127 | sdram_module = MT41J128M16(self.clk_freq, "1:4") 128 | self.add_constant("READ_LEVELING_BITSLIP", 3) 129 | self.add_constant("READ_LEVELING_DELAY", 14) 130 | self.register_sdram(self.ddrphy, 131 | sdram_module.geom_settings, 132 | sdram_module.timing_settings, 133 | controller_settings=ControllerSettings(with_bandwidth=True, 134 | cmd_buffer_depth=8, 135 | with_refresh=True)) 136 | 137 | 138 | class DMATestSoC(BaseSoC): 139 | def __init__(self, platform, *args, **kwargs): 140 | BaseSoC.__init__(self, platform, *args, **kwargs) 141 | 142 | # # # 143 | 144 | # parameters 145 | slot_length = 1280*720*32 146 | slot_offset = 0x00000000 147 | slot0_base = slot_offset + 0*slot_length 148 | slot1_base = slot_offset + 1*slot_length 149 | 150 | # create fake pixel clock 151 | self.clock_domains.cd_pix = ClockDomain() # Remove once hdmi in integrated 152 | self.comb += [ 153 | self.cd_pix.clk.eq(ClockSignal()), 154 | self.cd_pix.rst.eq(ResetSignal()) 155 | ] 156 | 157 | # dram dmas 158 | dma_writer = DMAWriter(self.sdram.crossbar.get_port(mode="write", dw=32, cd="pix")) 159 | dma_writer = ClockDomainsRenamer("pix")(dma_writer) 160 | dma_reader = DMAReader(self.sdram.crossbar.get_port(mode="read", dw=32, cd="pix")) 161 | dma_reader = ClockDomainsRenamer("pix")(dma_reader) 162 | self.submodules += dma_writer, dma_reader 163 | 164 | # quick "user manual" :) 165 | # user_sw0 : dma writer enable 166 | # user_sw1 : dma writer valid 167 | # user sw2 : dma reader enable 168 | # user sw3 : dma reader ready 169 | 170 | # user_btn0: dma writer start 171 | # user_btn1: dma_reader start 172 | # user_btn2: error injection 173 | 174 | # user_led0: dma_writer idle 175 | # user_led1: dma_writer ready 176 | # user_led2: dma_reader idle 177 | # user_led3: dma_reader valid 178 | 179 | # test 180 | idata0 = Signal(10) 181 | idata1 = Signal(10) 182 | idata2 = Signal(10) 183 | 184 | self.sync.pix += [ 185 | If(~platform.request("user_btn", 2), 186 | idata0.eq(idata0 + 1), 187 | idata1.eq(idata1 + 2), 188 | idata2.eq(idata2 + 4) 189 | ).Else( 190 | idata0.eq(0), 191 | idata1.eq(0), 192 | idata2.eq(0) 193 | ) 194 | ] 195 | 196 | # dma 197 | self.comb += [ 198 | # control 199 | dma_writer.enable.eq(platform.request("user_sw", 0)), 200 | dma_writer.slot0_base.eq(slot0_base), 201 | dma_writer.slot1_base.eq(slot1_base), 202 | dma_writer.length.eq(slot_length), 203 | 204 | # stream 205 | dma_writer.start.eq(platform.request("user_btn", 0)), 206 | platform.request("user_led", 0).eq(dma_writer.idle), 207 | dma_writer.sink.valid.eq(platform.request("user_sw", 1)), 208 | platform.request("user_led", 1).eq(dma_writer.sink.ready), 209 | dma_writer.sink.data[0:10].eq(idata0), 210 | dma_writer.sink.data[10:20].eq(idata1), 211 | dma_writer.sink.data[20:30].eq(idata2), 212 | ] 213 | 214 | # test 215 | odata0 = Signal(10) 216 | odata1 = Signal(10) 217 | odata2 = Signal(10) 218 | 219 | # hdmi out dma 220 | self.comb += [ 221 | # control 222 | dma_reader.enable.eq(platform.request("user_sw", 2)), 223 | dma_reader.slot0_base.eq(slot0_base), 224 | dma_reader.slot1_base.eq(slot1_base), 225 | dma_reader.length.eq(slot_length), 226 | 227 | # stream 228 | dma_reader.start.eq(platform.request("user_btn", 1)), 229 | platform.request("user_led", 2).eq(dma_reader.idle), 230 | platform.request("user_led", 3).eq(dma_reader.source.valid), 231 | dma_reader.source.ready.eq(platform.request("user_sw", 3)), 232 | odata0.eq(dma_reader.source.data[0:10]), 233 | odata1.eq(dma_reader.source.data[10:20]), 234 | odata2.eq(dma_reader.source.data[20:30]), 235 | ] 236 | 237 | # check 238 | odata0_d = Signal(10) 239 | odata1_d = Signal(10) 240 | odata2_d = Signal(10) 241 | 242 | errors = platform.request("rgb_leds") 243 | 244 | self.sync.pix += [ 245 | errors.r.eq(0b000), 246 | errors.g.eq(0b111), 247 | odata0_d.eq(odata0), 248 | odata1_d.eq(odata1), 249 | odata2_d.eq(odata2), 250 | If(odata0 != (odata0_d + 1), 251 | errors.r[0].eq(1), 252 | errors.g[0].eq(0)), 253 | If(odata1 != (odata1_d + 2), 254 | errors.r[1].eq(1), 255 | errors.g[1].eq(0)), 256 | If(odata2 != (odata2_d + 4), 257 | errors.r[2].eq(1), 258 | errors.g[2].eq(0)), 259 | ] 260 | 261 | def do_exit(self, vns): 262 | pass 263 | 264 | def main(): 265 | platform = arty.Platform() 266 | soc = DMATestSoC(platform) 267 | builder = Builder(soc, output_dir="build", csr_csv="test/csr.csv") 268 | vns = builder.build() 269 | soc.do_exit(vns) 270 | 271 | if __name__ == "__main__": 272 | main() 273 | -------------------------------------------------------------------------------- /firmware/hdmi_in0.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "flags.h" 12 | 13 | #ifdef CSR_HDMI_IN0_BASE 14 | 15 | #include "hdmi_in0.h" 16 | 17 | int hdmi_in0_debug; 18 | int hdmi_in0_fb_index; 19 | 20 | #define FRAMEBUFFER_COUNT 4 21 | #define FRAMEBUFFER_MASK (FRAMEBUFFER_COUNT - 1) 22 | 23 | #define HDMI_IN0_FRAMEBUFFERS_BASE (0x00000000 + 0x100000) 24 | #define HDMI_IN0_FRAMEBUFFERS_SIZE (1920*1080*4) 25 | 26 | //#define CLEAN_COMMUTATION 27 | #define DEBUG 28 | 29 | #define HDMI_IN0_PHASE_ADJUST_WER_THRESHOLD 10 30 | 31 | unsigned int hdmi_in0_framebuffer_base(char n) { 32 | return HDMI_IN0_FRAMEBUFFERS_BASE + n*HDMI_IN0_FRAMEBUFFERS_SIZE; 33 | } 34 | 35 | #ifdef HDMI_IN0_INTERRUPT 36 | static int hdmi_in0_fb_slot_indexes[2]; 37 | static int hdmi_in0_next_fb_index; 38 | #endif 39 | 40 | static int hdmi_in0_hres, hdmi_in0_vres; 41 | 42 | extern void processor_update(void); 43 | 44 | #ifdef HDMI_IN0_INTERRUPT 45 | void hdmi_in0_isr(void) 46 | { 47 | int fb_index = -1; 48 | int length; 49 | int expected_length; 50 | unsigned int address_min, address_max; 51 | 52 | printf ("+"); 53 | address_min = HDMI_IN0_FRAMEBUFFERS_BASE & 0x0fffffff; 54 | address_max = address_min + HDMI_IN0_FRAMEBUFFERS_SIZE*FRAMEBUFFER_COUNT; 55 | if((hdmi_in0_dma_slot0_status_read() == DVISAMPLER_SLOT_PENDING) 56 | && ((hdmi_in0_dma_slot0_address_read() < address_min) || (hdmi_in0_dma_slot0_address_read() > address_max))) 57 | printf("hdmi_in0: slot0: stray DMA\r\n"); 58 | if((hdmi_in0_dma_slot1_status_read() == DVISAMPLER_SLOT_PENDING) 59 | && ((hdmi_in0_dma_slot1_address_read() < address_min) || (hdmi_in0_dma_slot1_address_read() > address_max))) 60 | printf("hdmi_in0: slot1: stray DMA\r\n"); 61 | 62 | #ifdef CLEAN_COMMUTATION 63 | if((hdmi_in0_resdetection_hres_read() != hdmi_in0_hres) 64 | || (hdmi_in0_resdetection_vres_read() != hdmi_in0_vres)) { 65 | /* Dump frames until we get the expected resolution */ 66 | if(hdmi_in0_dma_slot0_status_read() == DVISAMPLER_SLOT_PENDING) { 67 | hdmi_in0_dma_slot0_address_write(hdmi_in0_framebuffer_base(hdmi_in0_fb_slot_indexes[0])); 68 | hdmi_in0_dma_slot0_status_write(DVISAMPLER_SLOT_LOADED); 69 | } 70 | if(hdmi_in0_dma_slot1_status_read() == DVISAMPLER_SLOT_PENDING) { 71 | hdmi_in0_dma_slot1_address_write(hdmi_in0_framebuffer_base(hdmi_in0_fb_slot_indexes[1])); 72 | hdmi_in0_dma_slot1_status_write(DVISAMPLER_SLOT_LOADED); 73 | } 74 | return; 75 | } 76 | #endif 77 | 78 | expected_length = hdmi_in0_hres*hdmi_in0_vres*2; 79 | if(hdmi_in0_dma_slot0_status_read() == DVISAMPLER_SLOT_PENDING) { 80 | length = hdmi_in0_dma_slot0_address_read() - (hdmi_in0_framebuffer_base(hdmi_in0_fb_slot_indexes[0]) & 0x0fffffff); 81 | if(length == expected_length) { 82 | fb_index = hdmi_in0_fb_slot_indexes[0]; 83 | hdmi_in0_fb_slot_indexes[0] = hdmi_in0_next_fb_index; 84 | hdmi_in0_next_fb_index = (hdmi_in0_next_fb_index + 1) & FRAMEBUFFER_MASK; 85 | } else { 86 | #ifdef DEBUG 87 | printf("hdmi_in0: slot0: unexpected frame length: %d\r\n", length); 88 | #endif 89 | } 90 | hdmi_in0_dma_slot0_address_write(hdmi_in0_framebuffer_base(hdmi_in0_fb_slot_indexes[0])); 91 | hdmi_in0_dma_slot0_status_write(DVISAMPLER_SLOT_LOADED); 92 | } 93 | if(hdmi_in0_dma_slot1_status_read() == DVISAMPLER_SLOT_PENDING) { 94 | length = hdmi_in0_dma_slot1_address_read() - (hdmi_in0_framebuffer_base(hdmi_in0_fb_slot_indexes[1]) & 0x0fffffff); 95 | if(length == expected_length) { 96 | fb_index = hdmi_in0_fb_slot_indexes[1]; 97 | hdmi_in0_fb_slot_indexes[1] = hdmi_in0_next_fb_index; 98 | hdmi_in0_next_fb_index = (hdmi_in0_next_fb_index + 1) & FRAMEBUFFER_MASK; 99 | } else { 100 | #ifdef DEBUG 101 | printf("hdmi_in0: slot1: unexpected frame length: %d\r\n", length); 102 | #endif 103 | } 104 | hdmi_in0_dma_slot1_address_write(hdmi_in0_framebuffer_base(hdmi_in0_fb_slot_indexes[1])); 105 | hdmi_in0_dma_slot1_status_write(DVISAMPLER_SLOT_LOADED); 106 | } 107 | 108 | if(fb_index != -1) 109 | hdmi_in0_fb_index = fb_index; 110 | processor_update(); 111 | } 112 | #endif 113 | 114 | static int hdmi_in0_connected; 115 | static int hdmi_in0_locked; 116 | 117 | void hdmi_in0_init_video(int hres, int vres) 118 | { 119 | hdmi_in0_clocking_mmcm_reset_write(1); 120 | hdmi_in0_connected = hdmi_in0_locked = 0; 121 | hdmi_in0_hres = hres; hdmi_in0_vres = vres; 122 | 123 | #ifdef HDMI_IN0_INTERRUPT 124 | unsigned int mask; 125 | 126 | puts( "setting up HDMI0 interrupts\n" ); 127 | 128 | hdmi_in0_dma_frame_size_write(hres*vres*2); 129 | hdmi_in0_fb_slot_indexes[0] = 0; 130 | hdmi_in0_dma_slot0_address_write(hdmi_in0_framebuffer_base(0)); 131 | hdmi_in0_dma_slot0_status_write(DVISAMPLER_SLOT_LOADED); 132 | hdmi_in0_fb_slot_indexes[1] = 1; 133 | hdmi_in0_dma_slot1_address_write(hdmi_in0_framebuffer_base(1)); 134 | hdmi_in0_dma_slot1_status_write(DVISAMPLER_SLOT_LOADED); 135 | hdmi_in0_next_fb_index = 2; 136 | 137 | hdmi_in0_dma_ev_pending_write(hdmi_in0_dma_ev_pending_read()); 138 | hdmi_in0_dma_ev_enable_write(0x3); 139 | mask = irq_getmask(); 140 | mask |= 1 << HDMI_IN0_INTERRUPT; 141 | irq_setmask(mask); 142 | 143 | hdmi_in0_fb_index = 3; 144 | #endif 145 | } 146 | 147 | void hdmi_in0_disable(void) 148 | { 149 | #ifdef HDMI_IN0_INTERRUPT 150 | unsigned int mask; 151 | 152 | mask = irq_getmask(); 153 | mask &= ~(1 << HDMI_IN0_INTERRUPT); 154 | irq_setmask(mask); 155 | 156 | hdmi_in0_dma_slot0_status_write(DVISAMPLER_SLOT_EMPTY); 157 | hdmi_in0_dma_slot1_status_write(DVISAMPLER_SLOT_EMPTY); 158 | #endif 159 | hdmi_in0_clocking_mmcm_reset_write(1); 160 | } 161 | 162 | void hdmi_in0_clear_framebuffers(void) 163 | { 164 | int i; 165 | flush_l2_cache(); 166 | volatile unsigned int *framebuffer = (unsigned int *)(MAIN_RAM_BASE + HDMI_IN0_FRAMEBUFFERS_BASE); 167 | for(i=0; i<(HDMI_IN0_FRAMEBUFFERS_SIZE*FRAMEBUFFER_COUNT)/4; i++) { 168 | framebuffer[i] = 0x80108010; /* black in YCbCr 4:2:2*/ 169 | } 170 | } 171 | 172 | static int hdmi_in0_d0, hdmi_in0_d1, hdmi_in0_d2; 173 | 174 | void hdmi_in0_print_status(void) 175 | { 176 | hdmi_in0_data0_wer_update_write(1); 177 | hdmi_in0_data1_wer_update_write(1); 178 | hdmi_in0_data2_wer_update_write(1); 179 | printf("hdmi_in0: ph:%4d %4d %4d // charsync:%d%d%d [%d %d %d] // WER:%3d %3d %3d // chansync:%d // res:%dx%d\r\n", 180 | hdmi_in0_d0, hdmi_in0_d1, hdmi_in0_d2, 181 | hdmi_in0_data0_charsync_char_synced_read(), 182 | hdmi_in0_data1_charsync_char_synced_read(), 183 | hdmi_in0_data2_charsync_char_synced_read(), 184 | hdmi_in0_data0_charsync_ctl_pos_read(), 185 | hdmi_in0_data1_charsync_ctl_pos_read(), 186 | hdmi_in0_data2_charsync_ctl_pos_read(), 187 | hdmi_in0_data0_wer_value_read(), 188 | hdmi_in0_data1_wer_value_read(), 189 | hdmi_in0_data2_wer_value_read(), 190 | hdmi_in0_chansync_channels_synced_read(), 191 | hdmi_in0_resdetection_hres_read(), 192 | hdmi_in0_resdetection_vres_read()); 193 | } 194 | 195 | int hdmi_in0_calibrate_delays(int freq) 196 | { 197 | int i, phase_detector_delay; 198 | 199 | hdmi_in0_data0_cap_dly_ctl_write(DVISAMPLER_DELAY_RST); 200 | hdmi_in0_data1_cap_dly_ctl_write(DVISAMPLER_DELAY_RST); 201 | hdmi_in0_data2_cap_dly_ctl_write(DVISAMPLER_DELAY_RST); 202 | hdmi_in0_data0_cap_phase_reset_write(1); 203 | hdmi_in0_data1_cap_phase_reset_write(1); 204 | hdmi_in0_data2_cap_phase_reset_write(1); 205 | hdmi_in0_d0 = hdmi_in0_d1 = hdmi_in0_d2 = 0; 206 | 207 | /* preload slave phase detector idelay with 90° phase shift 208 | (78 ps taps on 7-series) */ 209 | phase_detector_delay = 10000000/(4*freq*78); 210 | for(i=0; i 3) { 303 | printf("hdmi_in0: giving up\r\n"); 304 | hdmi_in0_calibrate_delays(freq); 305 | return 0; 306 | } 307 | } 308 | } 309 | } 310 | 311 | static void hdmi_in0_check_overflow(void) 312 | { 313 | #ifdef HDMI_IN0_INTERRUPT 314 | if(hdmi_in0_frame_overflow_read()) { 315 | printf("hdmi_in0: FIFO overflow\r\n"); 316 | hdmi_in0_frame_overflow_write(1); 317 | } 318 | #endif 319 | } 320 | 321 | static int hdmi_in0_clocking_locked_filtered(void) 322 | { 323 | static int lock_start_time; 324 | static int lock_status; 325 | 326 | if(hdmi_in0_clocking_locked_read()) { 327 | switch(lock_status) { 328 | case 0: 329 | elapsed(&lock_start_time, -1); 330 | lock_status = 1; 331 | break; 332 | case 1: 333 | if(elapsed(&lock_start_time, SYSTEM_CLOCK_FREQUENCY/4)) 334 | lock_status = 2; 335 | break; 336 | case 2: 337 | return 1; 338 | } 339 | } else 340 | lock_status = 0; 341 | return 0; 342 | } 343 | 344 | static int hdmi_in0_get_wer(void){ 345 | int wer = 0; 346 | wer += hdmi_in0_data0_wer_value_read(); 347 | wer += hdmi_in0_data1_wer_value_read(); 348 | wer += hdmi_in0_data2_wer_value_read(); 349 | return wer; 350 | } 351 | 352 | void hdmi_in0_service(int freq) 353 | { 354 | static int last_event; 355 | 356 | if(hdmi_in0_connected) { 357 | if(!hdmi_in0_edid_hpd_notif_read()) { 358 | if(hdmi_in0_debug) 359 | printf("hdmi_in0: disconnected\r\n"); 360 | hdmi_in0_connected = 0; 361 | hdmi_in0_locked = 0; 362 | hdmi_in0_clocking_mmcm_reset_write(1); 363 | hdmi_in0_clear_framebuffers(); 364 | } else { 365 | if(hdmi_in0_locked) { 366 | if(hdmi_in0_clocking_locked_filtered()) { 367 | if(elapsed(&last_event, SYSTEM_CLOCK_FREQUENCY/2)) { 368 | hdmi_in0_data0_wer_update_write(1); 369 | hdmi_in0_data1_wer_update_write(1); 370 | hdmi_in0_data2_wer_update_write(1); 371 | if(hdmi_in0_debug) 372 | hdmi_in0_print_status(); 373 | if(hdmi_in0_get_wer() >= HDMI_IN0_PHASE_ADJUST_WER_THRESHOLD) 374 | hdmi_in0_adjust_phase(); 375 | } 376 | } else { 377 | if(hdmi_in0_debug) 378 | printf("hdmi_in0: lost PLL lock\r\n"); 379 | hdmi_in0_locked = 0; 380 | hdmi_in0_clear_framebuffers(); 381 | } 382 | } else { 383 | if(hdmi_in0_clocking_locked_filtered()) { 384 | if(hdmi_in0_debug) 385 | printf("hdmi_in0: PLL locked\r\n"); 386 | hdmi_in0_phase_startup(freq); 387 | if(hdmi_in0_debug) 388 | hdmi_in0_print_status(); 389 | hdmi_in0_locked = 1; 390 | } 391 | } 392 | } 393 | } else { 394 | if(hdmi_in0_edid_hpd_notif_read()) { 395 | if(hdmi_in0_debug) 396 | printf("hdmi_in0: connected\r\n"); 397 | hdmi_in0_connected = 1; 398 | hdmi_in0_clocking_mmcm_reset_write(0); 399 | } 400 | } 401 | hdmi_in0_check_overflow(); 402 | } 403 | 404 | #endif 405 | -------------------------------------------------------------------------------- /firmware/hdmi_in1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "flags.h" 12 | 13 | #ifdef CSR_HDMI_IN1_BASE 14 | 15 | #include "hdmi_in1.h" 16 | 17 | int hdmi_in1_debug; 18 | int hdmi_in1_fb_index; 19 | 20 | #define FRAMEBUFFER_COUNT 4 21 | #define FRAMEBUFFER_MASK (FRAMEBUFFER_COUNT - 1) 22 | 23 | //#define HDMI_IN1_FRAMEBUFFERS_BASE (0x00000000 + 0x100000) 24 | #define HDMI_IN1_FRAMEBUFFERS_BASE (0x04018000) 25 | #define HDMI_IN1_FRAMEBUFFERS_SIZE (1920*1080*4) 26 | 27 | //#define CLEAN_COMMUTATION 28 | #define DEBUG 29 | 30 | #define HDMI_IN1_PHASE_ADJUST_WER_THRESHOLD 10 31 | 32 | unsigned int hdmi_in1_framebuffer_base(char n) { 33 | return HDMI_IN1_FRAMEBUFFERS_BASE + n*HDMI_IN1_FRAMEBUFFERS_SIZE; 34 | } 35 | 36 | #ifdef HDMI_IN1_INTERRUPT 37 | static int hdmi_in1_fb_slot_indexes[2]; 38 | static int hdmi_in1_next_fb_index; 39 | #endif 40 | 41 | static int hdmi_in1_hres, hdmi_in1_vres; 42 | 43 | extern void processor_update(void); 44 | 45 | #ifdef HDMI_IN1_INTERRUPT 46 | void hdmi_in1_isr(void) 47 | { 48 | int fb_index = -1; 49 | int length; 50 | int expected_length; 51 | unsigned int address_min, address_max; 52 | 53 | address_min = HDMI_IN1_FRAMEBUFFERS_BASE & 0x0fffffff; 54 | address_max = address_min + HDMI_IN1_FRAMEBUFFERS_SIZE*FRAMEBUFFER_COUNT; 55 | if((hdmi_in1_dma_slot0_status_read() == DVISAMPLER_SLOT_PENDING) 56 | && ((hdmi_in1_dma_slot0_address_read() < address_min) || (hdmi_in1_dma_slot0_address_read() > address_max))) 57 | printf("hdmi_in1: slot0: stray DMA\r\n"); 58 | if((hdmi_in1_dma_slot1_status_read() == DVISAMPLER_SLOT_PENDING) 59 | && ((hdmi_in1_dma_slot1_address_read() < address_min) || (hdmi_in1_dma_slot1_address_read() > address_max))) 60 | printf("hdmi_in1: slot1: stray DMA\r\n"); 61 | 62 | #ifdef CLEAN_COMMUTATION 63 | if((hdmi_in1_resdetection_hres_read() != hdmi_in1_hres) 64 | || (hdmi_in1_resdetection_vres_read() != hdmi_in1_vres)) { 65 | /* Dump frames until we get the expected resolution */ 66 | if(hdmi_in1_dma_slot0_status_read() == DVISAMPLER_SLOT_PENDING) { 67 | hdmi_in1_dma_slot0_address_write(hdmi_in1_framebuffer_base(hdmi_in1_fb_slot_indexes[0])); 68 | hdmi_in1_dma_slot0_status_write(DVISAMPLER_SLOT_LOADED); 69 | } 70 | if(hdmi_in1_dma_slot1_status_read() == DVISAMPLER_SLOT_PENDING) { 71 | hdmi_in1_dma_slot1_address_write(hdmi_in1_framebuffer_base(hdmi_in1_fb_slot_indexes[1])); 72 | hdmi_in1_dma_slot1_status_write(DVISAMPLER_SLOT_LOADED); 73 | } 74 | return; 75 | } 76 | #endif 77 | 78 | expected_length = hdmi_in1_hres*hdmi_in1_vres*4; 79 | if(hdmi_in1_dma_slot0_status_read() == DVISAMPLER_SLOT_PENDING) { 80 | length = hdmi_in1_dma_slot0_address_read() - (hdmi_in1_framebuffer_base(hdmi_in1_fb_slot_indexes[0]) & 0x0fffffff); 81 | if(length == expected_length) { 82 | fb_index = hdmi_in1_fb_slot_indexes[0]; 83 | hdmi_in1_fb_slot_indexes[0] = hdmi_in1_next_fb_index; 84 | hdmi_in1_next_fb_index = (hdmi_in1_next_fb_index + 1) & FRAMEBUFFER_MASK; 85 | } else { 86 | #ifdef DEBUG 87 | printf("hdmi_in1: slot0: unexpected frame length: %d\r\n", length); 88 | #endif 89 | } 90 | hdmi_in1_dma_slot0_address_write(hdmi_in1_framebuffer_base(hdmi_in1_fb_slot_indexes[0])); 91 | hdmi_in1_dma_slot0_status_write(DVISAMPLER_SLOT_LOADED); 92 | } 93 | if(hdmi_in1_dma_slot1_status_read() == DVISAMPLER_SLOT_PENDING) { 94 | length = hdmi_in1_dma_slot1_address_read() - (hdmi_in1_framebuffer_base(hdmi_in1_fb_slot_indexes[1]) & 0x0fffffff); 95 | if(length == expected_length) { 96 | fb_index = hdmi_in1_fb_slot_indexes[1]; 97 | hdmi_in1_fb_slot_indexes[1] = hdmi_in1_next_fb_index; 98 | hdmi_in1_next_fb_index = (hdmi_in1_next_fb_index + 1) & FRAMEBUFFER_MASK; 99 | } else { 100 | #ifdef DEBUG 101 | printf("hdmi_in1: slot1: unexpected frame length: %d\r\n", length); 102 | #endif 103 | } 104 | hdmi_in1_dma_slot1_address_write(hdmi_in1_framebuffer_base(hdmi_in1_fb_slot_indexes[1])); 105 | hdmi_in1_dma_slot1_status_write(DVISAMPLER_SLOT_LOADED); 106 | } 107 | 108 | if(fb_index != -1) 109 | hdmi_in1_fb_index = fb_index; 110 | processor_update(); 111 | 112 | } 113 | #endif 114 | 115 | static int hdmi_in1_connected; 116 | static int hdmi_in1_locked; 117 | 118 | void hdmi_in1_init_video(int hres, int vres) 119 | { 120 | hdmi_in1_clocking_mmcm_reset_write(1); 121 | hdmi_in1_connected = hdmi_in1_locked = 0; 122 | hdmi_in1_hres = hres; hdmi_in1_vres = vres; 123 | 124 | #ifdef HDMI_IN1_INTERRUPT 125 | unsigned int mask; 126 | 127 | printf( "setting up HDMI1 interrupts, hres: %d vres: %d\n", hdmi_in1_hres, hdmi_in1_vres ); 128 | 129 | hdmi_in1_dma_frame_size_write(hres*vres*4); 130 | hdmi_in1_fb_slot_indexes[0] = 0; 131 | hdmi_in1_dma_slot0_address_write(hdmi_in1_framebuffer_base(0)); 132 | printf( "slot0 %x\n", hdmi_in1_framebuffer_base(0) ); 133 | hdmi_in1_dma_slot0_status_write(DVISAMPLER_SLOT_LOADED); 134 | hdmi_in1_fb_slot_indexes[1] = 1; 135 | hdmi_in1_dma_slot1_address_write(hdmi_in1_framebuffer_base(1)); 136 | printf( "slot1 %x\n", hdmi_in1_framebuffer_base(1) ); 137 | hdmi_in1_dma_slot1_status_write(DVISAMPLER_SLOT_LOADED); 138 | hdmi_in1_next_fb_index = 2; 139 | 140 | hdmi_in1_dma_ev_pending_write(hdmi_in1_dma_ev_pending_read()); 141 | hdmi_in1_dma_ev_enable_write(0x3); 142 | mask = irq_getmask(); 143 | mask |= 1 << HDMI_IN1_INTERRUPT; 144 | printf( "irq mask: %x\n", mask ); 145 | irq_setmask(mask); 146 | 147 | hdmi_in1_fb_index = 3; 148 | #endif 149 | } 150 | 151 | void hdmi_in1_disable(void) 152 | { 153 | #ifdef HDMI_IN1_INTERRUPT 154 | unsigned int mask; 155 | 156 | mask = irq_getmask(); 157 | mask &= ~(1 << HDMI_IN1_INTERRUPT); 158 | irq_setmask(mask); 159 | 160 | hdmi_in1_dma_slot0_status_write(DVISAMPLER_SLOT_EMPTY); 161 | hdmi_in1_dma_slot1_status_write(DVISAMPLER_SLOT_EMPTY); 162 | #endif 163 | hdmi_in1_clocking_mmcm_reset_write(1); 164 | } 165 | 166 | void hdmi_in1_clear_framebuffers(void) 167 | { 168 | int i; 169 | flush_l2_cache(); 170 | 171 | volatile unsigned int *framebuffer = (unsigned int *)(MAIN_RAM_BASE + HDMI_IN1_FRAMEBUFFERS_BASE); 172 | for(i=0; i<(HDMI_IN1_FRAMEBUFFERS_SIZE*FRAMEBUFFER_COUNT)/4; i++) { 173 | framebuffer[i] = 0x80108010; /* black in YCbCr 4:2:2*/ 174 | } 175 | } 176 | 177 | static int hdmi_in1_d0, hdmi_in1_d1, hdmi_in1_d2; 178 | 179 | void hdmi_in1_print_status(void) 180 | { 181 | hdmi_in1_data0_wer_update_write(1); 182 | hdmi_in1_data1_wer_update_write(1); 183 | hdmi_in1_data2_wer_update_write(1); 184 | printf("hdmi_in1: ph:%4d %4d %4d // charsync:%d%d%d [%d %d %d] // WER:%3d %3d %3d // chansync:%d // res:%dx%d\r\n", 185 | hdmi_in1_d0, hdmi_in1_d1, hdmi_in1_d2, 186 | hdmi_in1_data0_charsync_char_synced_read(), 187 | hdmi_in1_data1_charsync_char_synced_read(), 188 | hdmi_in1_data2_charsync_char_synced_read(), 189 | hdmi_in1_data0_charsync_ctl_pos_read(), 190 | hdmi_in1_data1_charsync_ctl_pos_read(), 191 | hdmi_in1_data2_charsync_ctl_pos_read(), 192 | hdmi_in1_data0_wer_value_read(), 193 | hdmi_in1_data1_wer_value_read(), 194 | hdmi_in1_data2_wer_value_read(), 195 | hdmi_in1_chansync_channels_synced_read(), 196 | hdmi_in1_resdetection_hres_read(), 197 | hdmi_in1_resdetection_vres_read()); 198 | } 199 | 200 | int hdmi_in1_calibrate_delays(int freq) 201 | { 202 | int i, phase_detector_delay; 203 | 204 | hdmi_in1_data0_cap_dly_ctl_write(DVISAMPLER_DELAY_RST); 205 | hdmi_in1_data1_cap_dly_ctl_write(DVISAMPLER_DELAY_RST); 206 | hdmi_in1_data2_cap_dly_ctl_write(DVISAMPLER_DELAY_RST); 207 | hdmi_in1_data0_cap_phase_reset_write(1); 208 | hdmi_in1_data1_cap_phase_reset_write(1); 209 | hdmi_in1_data2_cap_phase_reset_write(1); 210 | hdmi_in1_d0 = hdmi_in1_d1 = hdmi_in1_d2 = 0; 211 | 212 | /* preload slave phase detector idelay with 90° phase shift 213 | (78 ps taps on 7-series) */ 214 | phase_detector_delay = 10000000/(4*freq*78); 215 | for(i=0; i 3) { 308 | printf("hdmi_in1: giving up\r\n"); 309 | hdmi_in1_calibrate_delays(freq); 310 | return 0; 311 | } 312 | } 313 | } 314 | } 315 | 316 | static void hdmi_in1_check_overflow(void) 317 | { 318 | #ifdef HDMI_IN1_INTERRUPT 319 | if(hdmi_in1_frame_overflow_read()) { 320 | printf("hdmi_in1: FIFO overflow\r\n"); 321 | hdmi_in1_frame_overflow_write(1); 322 | } 323 | #endif 324 | } 325 | 326 | static int hdmi_in1_clocking_locked_filtered(void) 327 | { 328 | static int lock_start_time; 329 | static int lock_status; 330 | 331 | if(hdmi_in1_clocking_locked_read()) { 332 | switch(lock_status) { 333 | case 0: 334 | elapsed(&lock_start_time, -1); 335 | lock_status = 1; 336 | break; 337 | case 1: 338 | if(elapsed(&lock_start_time, SYSTEM_CLOCK_FREQUENCY/4)) 339 | lock_status = 2; 340 | break; 341 | case 2: 342 | return 1; 343 | } 344 | } else 345 | lock_status = 0; 346 | return 0; 347 | } 348 | 349 | static int hdmi_in1_get_wer(void){ 350 | int wer = 0; 351 | wer += hdmi_in1_data0_wer_value_read(); 352 | wer += hdmi_in1_data1_wer_value_read(); 353 | wer += hdmi_in1_data2_wer_value_read(); 354 | return wer; 355 | } 356 | 357 | void hdmi_in1_service(int freq) 358 | { 359 | static int last_event; 360 | 361 | if(hdmi_in1_connected) { 362 | if(!hdmi_in1_edid_hpd_notif_read()) { 363 | if(hdmi_in1_debug) 364 | printf("hdmi_in1: disconnected\r\n"); 365 | hdmi_in1_connected = 0; 366 | hdmi_in1_locked = 0; 367 | hdmi_in1_clocking_mmcm_reset_write(1); 368 | hdmi_in1_clear_framebuffers(); 369 | } else { 370 | if(hdmi_in1_locked) { 371 | if(hdmi_in1_clocking_locked_filtered()) { 372 | if(elapsed(&last_event, SYSTEM_CLOCK_FREQUENCY/2)) { 373 | hdmi_in1_data0_wer_update_write(1); 374 | hdmi_in1_data1_wer_update_write(1); 375 | hdmi_in1_data2_wer_update_write(1); 376 | if(hdmi_in1_debug) 377 | hdmi_in1_print_status(); 378 | if(hdmi_in1_get_wer() >= HDMI_IN1_PHASE_ADJUST_WER_THRESHOLD) 379 | hdmi_in1_adjust_phase(); 380 | } 381 | } else { 382 | if(hdmi_in1_debug) 383 | printf("hdmi_in1: lost PLL lock\r\n"); 384 | hdmi_in1_locked = 0; 385 | hdmi_in1_clear_framebuffers(); 386 | } 387 | } else { 388 | if(hdmi_in1_clocking_locked_filtered()) { 389 | if(hdmi_in1_debug) 390 | printf("hdmi_in1: PLL locked\r\n"); 391 | hdmi_in1_phase_startup(freq); 392 | if(hdmi_in1_debug) 393 | hdmi_in1_print_status(); 394 | hdmi_in1_locked = 1; 395 | } 396 | } 397 | } 398 | } else { 399 | if(hdmi_in1_edid_hpd_notif_read()) { 400 | if(hdmi_in1_debug) 401 | printf("hdmi_in1: connected\r\n"); 402 | hdmi_in1_connected = 1; 403 | hdmi_in1_clocking_mmcm_reset_write(0); 404 | } 405 | } 406 | hdmi_in1_check_overflow(); 407 | } 408 | 409 | #endif 410 | -------------------------------------------------------------------------------- /netv2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import os 4 | 5 | from litex.gen import * 6 | from litex.gen.genlib.resetsync import AsyncResetSynchronizer 7 | 8 | from litex.build.generic_platform import * 9 | from litex.build.xilinx import XilinxPlatform 10 | 11 | from litex.soc.integration.soc_core import mem_decoder 12 | from litex.soc.integration.soc_sdram import * 13 | from litex.soc.integration.builder import * 14 | from litex.soc.cores import dna, xadc 15 | from litex.soc.cores.frequency_meter import FrequencyMeter 16 | 17 | from litedram.modules import MT41J128M16 18 | from litedram.phy import a7ddrphy 19 | from litedram.core import ControllerSettings 20 | 21 | from litepcie.phy.s7pciephy import S7PCIEPHY 22 | from litepcie.core import LitePCIeEndpoint, LitePCIeMSI 23 | from litepcie.frontend.dma import LitePCIeDMA 24 | from litepcie.frontend.wishbone import LitePCIeWishboneBridge 25 | 26 | from litevideo.input import HDMIIn 27 | from litevideo.output import VideoOut 28 | 29 | import cpu_interface 30 | 31 | 32 | _io = [ 33 | ("clk50", 0, Pins("R2"), IOStandard("LVCMOS33")), 34 | 35 | ("user_led", 0, Pins("U2"), IOStandard("LVCMOS33")), 36 | 37 | ("serial", 0, 38 | Subsignal("tx", Pins("M5")), 39 | Subsignal("rx", Pins("N6")), 40 | IOStandard("LVCMOS33"), 41 | ), 42 | 43 | ("ddram", 0, 44 | Subsignal("a", Pins( 45 | "U15 M17 N18 U16 R18 P18 T18 T17", 46 | "U17 N16 R16 N17 V17 R17"), 47 | IOStandard("SSTL15")), 48 | Subsignal("ba", Pins("T15 M16 P15"), IOStandard("SSTL15")), 49 | Subsignal("ras_n", Pins("L18"), IOStandard("SSTL15")), 50 | Subsignal("cas_n", Pins("K17"), IOStandard("SSTL15")), 51 | Subsignal("we_n", Pins("P16"), IOStandard("SSTL15")), 52 | Subsignal("dm", Pins("D9 B14 F14 C18"), IOStandard("SSTL15")), 53 | Subsignal("dq", Pins( 54 | "D11 B11 D8 C11 C8 B10 C9 A10 " 55 | "A15 A14 E13 B12 C13 A12 D13 A13 " 56 | "H18 G17 G16 F17 G14 E18 H16 H17 " 57 | "C17 D16 B17 E16 C16 E17 D15 D18 " 58 | ), 59 | IOStandard("SSTL15"), 60 | Misc("IN_TERM=UNTUNED_SPLIT_50")), 61 | Subsignal("dqs_p", Pins("B9 C14 G15 B16"), IOStandard("DIFF_SSTL15")), 62 | Subsignal("dqs_n", Pins("A9 B15 F15 A17"), IOStandard("DIFF_SSTL15")), 63 | Subsignal("clk_p", Pins("P14"), IOStandard("DIFF_SSTL15")), 64 | Subsignal("clk_n", Pins("R15"), IOStandard("DIFF_SSTL15")), 65 | Subsignal("cke", Pins("K15"), IOStandard("SSTL15")), 66 | Subsignal("odt", Pins("K18"), IOStandard("SSTL15")), 67 | Subsignal("reset_n", Pins("V16"), IOStandard("LVCMOS15")), 68 | Subsignal("cs_n", Pins("J16"), IOStandard("SSTL15")), 69 | Misc("SLEW=FAST"), 70 | ), 71 | 72 | ("pcie_x1", 0, 73 | Subsignal("rst_n", Pins("N1"), IOStandard("LVCMOS33")), 74 | Subsignal("clk_p", Pins("D6")), 75 | Subsignal("clk_n", Pins("D5")), 76 | Subsignal("rx_p", Pins("E4")), 77 | Subsignal("rx_n", Pins("E3")), 78 | Subsignal("tx_p", Pins("H2")), 79 | Subsignal("tx_n", Pins("H1")) 80 | ), 81 | 82 | ("hdmi_in", 0, 83 | Subsignal("clk_p", Pins("P4"), IOStandard("TMDS_33")), 84 | Subsignal("clk_n", Pins("P3"), IOStandard("TMDS_33")), 85 | Subsignal("data0_p", Pins("U4"), IOStandard("TMDS_33")), 86 | Subsignal("data0_n", Pins("V4"), IOStandard("TMDS_33")), 87 | Subsignal("data1_p", Pins("P6"), IOStandard("TMDS_33")), 88 | Subsignal("data1_n", Pins("P5"), IOStandard("TMDS_33")), 89 | Subsignal("data2_p", Pins("R7"), IOStandard("TMDS_33")), 90 | Subsignal("data2_n", Pins("T7"), IOStandard("TMDS_33")), 91 | Subsignal("scl", Pins("K5"), IOStandard("LVCMOS33")), # FPIO5 (not connected) 92 | Subsignal("sda", Pins("J5"), IOStandard("LVCMOS33")), # FPIO4 (not connected) 93 | ), 94 | 95 | ("hdmi_out", 0, 96 | Subsignal("clk_p", Pins("R3"), IOStandard("TMDS_33")), 97 | Subsignal("clk_n", Pins("T2"), IOStandard("TMDS_33")), 98 | Subsignal("data0_p", Pins("T4"), IOStandard("TMDS_33")), 99 | Subsignal("data0_n", Pins("T3"), IOStandard("TMDS_33")), 100 | Subsignal("data1_p", Pins("U6"), IOStandard("TMDS_33")), 101 | Subsignal("data1_n", Pins("U5"), IOStandard("TMDS_33")), 102 | Subsignal("data2_p", Pins("V7"), IOStandard("TMDS_33")), 103 | Subsignal("data2_n", Pins("V6"), IOStandard("TMDS_33")), 104 | ), 105 | 106 | ("hdmi_sda_over_up", 0, Pins("V7"), IOStandard("LVCMOS33")), 107 | ("hdmi_sda_over_dn", 0, Pins("R6"), IOStandard("LVCMOS33")), 108 | ("hdmi_hdp_over", 0, Pins("V8"), IOStandard("LVCMOS33")), 109 | 110 | ] 111 | 112 | 113 | class Platform(XilinxPlatform): 114 | def __init__(self, toolchain="vivado", programmer="vivado"): 115 | XilinxPlatform.__init__(self, "xc7a50t-csg325-2", _io, 116 | toolchain=toolchain) 117 | 118 | self.add_platform_command( 119 | "set_property CONFIG_VOLTAGE 1.5 [current_design]") 120 | self.add_platform_command( 121 | "set_property CFGBVS GND [current_design]") 122 | self.add_platform_command( 123 | "set_property BITSTREAM.CONFIG.CONFIGRATE 22 [current_design]") 124 | self.add_platform_command( 125 | "set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]") 126 | self.toolchain.bitstream_commands = [ 127 | "set_property CONFIG_VOLTAGE 1.5 [current_design]", 128 | "set_property CFGBVS GND [current_design]", 129 | "set_property BITSTREAM.CONFIG.CONFIGRATE 22 [current_design]", 130 | "set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]", 131 | ] 132 | self.toolchain.additional_commands = \ 133 | ["write_cfgmem -verbose -force -format bin -interface spix1 -size 64 " 134 | "-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"] 135 | self.programmer = programmer 136 | 137 | self.add_platform_command(""" 138 | create_clock -name pcie_phy_clk -period 10.0 [get_pins {{pcie_phy/pcie_support_i/pcie_i/inst/inst/gt_top_i/pipe_wrapper_i/pipe_lane[0].gt_wrapper_i/gtp_channel.gtpe2_channel_i/TXOUTCLK}}] 139 | """) 140 | 141 | def create_programmer(self): 142 | if self.programmer == "vivado": 143 | return VivadoProgrammer(flash_part="n25q128-3.3v-spi-x1_x2_x4") 144 | else: 145 | raise ValueError("{} programmer is not supported" 146 | .format(self.programmer)) 147 | 148 | def do_finalize(self, fragment): 149 | XilinxPlatform.do_finalize(self, fragment) 150 | 151 | 152 | def csr_map_update(csr_map, csr_peripherals): 153 | csr_map.update(dict((n, v) 154 | for v, n in enumerate(csr_peripherals, start=max(csr_map.values()) + 1))) 155 | 156 | 157 | def period_ns(freq): 158 | return 1e9/freq 159 | 160 | 161 | class CRG(Module): 162 | def __init__(self, platform): 163 | self.clock_domains.cd_sys = ClockDomain() 164 | self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) 165 | self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True) 166 | self.clock_domains.cd_clk200 = ClockDomain() 167 | self.clock_domains.cd_clk100 = ClockDomain() 168 | 169 | clk50 = platform.request("clk50") 170 | rst = Signal() 171 | 172 | pll_locked = Signal() 173 | pll_fb = Signal() 174 | self.pll_sys = Signal() 175 | pll_sys4x = Signal() 176 | pll_sys4x_dqs = Signal() 177 | pll_clk200 = Signal() 178 | self.specials += [ 179 | Instance("PLLE2_BASE", 180 | p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, 181 | 182 | # VCO @ 1600 MHz 183 | p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=20.0, 184 | p_CLKFBOUT_MULT=32, p_DIVCLK_DIVIDE=1, 185 | i_CLKIN1=clk50, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, 186 | 187 | # 100 MHz 188 | p_CLKOUT0_DIVIDE=16, p_CLKOUT0_PHASE=0.0, 189 | o_CLKOUT0=self.pll_sys, 190 | 191 | # 400 MHz 192 | p_CLKOUT1_DIVIDE=4, p_CLKOUT1_PHASE=0.0, 193 | o_CLKOUT1=pll_sys4x, 194 | 195 | # 400 MHz dqs 196 | p_CLKOUT2_DIVIDE=4, p_CLKOUT2_PHASE=90.0, 197 | o_CLKOUT2=pll_sys4x_dqs, 198 | 199 | # 200 MHz 200 | p_CLKOUT3_DIVIDE=8, p_CLKOUT3_PHASE=0.0, 201 | o_CLKOUT3=pll_clk200 202 | ), 203 | Instance("BUFG", i_I=self.pll_sys, o_O=self.cd_sys.clk), 204 | Instance("BUFG", i_I=self.pll_sys, o_O=self.cd_clk100.clk), 205 | Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), 206 | Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), 207 | Instance("BUFG", i_I=pll_sys4x_dqs, o_O=self.cd_sys4x_dqs.clk), 208 | AsyncResetSynchronizer(self.cd_sys, ~pll_locked | rst), 209 | AsyncResetSynchronizer(self.cd_clk200, ~pll_locked | rst), 210 | AsyncResetSynchronizer(self.cd_clk100, ~pll_locked | rst) 211 | ] 212 | 213 | reset_counter = Signal(4, reset=15) 214 | ic_reset = Signal(reset=1) 215 | self.sync.clk200 += \ 216 | If(reset_counter != 0, 217 | reset_counter.eq(reset_counter - 1) 218 | ).Else( 219 | ic_reset.eq(0) 220 | ) 221 | self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset) 222 | 223 | 224 | class BaseSoC(SoCSDRAM): 225 | csr_peripherals = { 226 | "ddrphy", 227 | "dna", 228 | "xadc", 229 | } 230 | csr_map_update(SoCSDRAM.csr_map, csr_peripherals) 231 | 232 | def __init__(self, platform, **kwargs): 233 | clk_freq = int(100e6) 234 | SoCSDRAM.__init__(self, platform, clk_freq, 235 | integrated_rom_size=0x8000, 236 | integrated_sram_size=0x8000, 237 | ident="NeTV2 LiteX Base SoC", 238 | reserve_nmi_interrupt=False, 239 | **kwargs) 240 | 241 | self.submodules.crg = CRG(platform) 242 | self.submodules.dna = dna.DNA() 243 | self.submodules.xadc = xadc.XADC() 244 | 245 | self.crg.cd_sys.clk.attr.add("keep") 246 | self.platform.add_period_constraint(self.crg.cd_sys.clk, period_ns(100e6)) 247 | 248 | # sdram 249 | self.submodules.ddrphy = a7ddrphy.A7DDRPHY(platform.request("ddram")) 250 | sdram_module = MT41J128M16(self.clk_freq, "1:4") 251 | self.add_constant("READ_LEVELING_BITSLIP", 3) 252 | self.add_constant("READ_LEVELING_DELAY", 14) 253 | self.register_sdram(self.ddrphy, 254 | sdram_module.geom_settings, 255 | sdram_module.timing_settings, 256 | controller_settings=ControllerSettings(with_bandwidth=True, 257 | cmd_buffer_depth=8, 258 | with_refresh=True)) 259 | 260 | # common led 261 | self.sys_led = Signal() 262 | self.pcie_led = Signal() 263 | self.comb += platform.request("user_led", 0).eq(self.sys_led ^ self.pcie_led) 264 | 265 | # sys led 266 | sys_counter = Signal(32) 267 | self.sync += sys_counter.eq(sys_counter + 1) 268 | self.comb += self.sys_led.eq(sys_counter[26]) 269 | 270 | 271 | class PCIeSoC(BaseSoC): 272 | csr_map = { 273 | "pcie_phy": 20, 274 | "dma": 21, 275 | "msi": 22, 276 | } 277 | csr_map.update(BaseSoC.csr_map) 278 | 279 | BaseSoC.mem_map["csr"] = 0x00000000 280 | BaseSoC.mem_map["rom"] = 0x20000000 281 | 282 | def __init__(self, platform, **kwargs): 283 | BaseSoC.__init__(self, platform, csr_data_width=32, **kwargs) 284 | 285 | # pcie phy 286 | self.submodules.pcie_phy = S7PCIEPHY(platform, platform.request("pcie_x1")) 287 | self.platform.add_false_path_constraints( 288 | self.crg.cd_sys.clk, 289 | self.pcie_phy.cd_pcie.clk) 290 | 291 | # pcie endpoint 292 | self.submodules.pcie_endpoint = LitePCIeEndpoint(self.pcie_phy, with_reordering=True) 293 | 294 | # pcie wishbone bridge 295 | self.submodules.pcie_wishbone = LitePCIeWishboneBridge(self.pcie_endpoint, lambda a: 1) 296 | self.add_wb_master(self.pcie_wishbone.wishbone) 297 | 298 | # pcie dma 299 | self.submodules.dma = LitePCIeDMA(self.pcie_phy, self.pcie_endpoint, with_loopback=True) 300 | self.dma.source.connect(self.dma.sink) 301 | 302 | # pcie msi 303 | self.submodules.msi = LitePCIeMSI() 304 | self.comb += self.msi.source.connect(self.pcie_phy.msi) 305 | self.interrupts = { 306 | "DMA_WRITER": self.dma.writer.irq, 307 | "DMA_READER": self.dma.reader.irq 308 | } 309 | for i, (k, v) in enumerate(sorted(self.interrupts.items())): 310 | self.comb += self.msi.irqs[i].eq(v) 311 | self.add_constant(k + "_INTERRUPT", i) 312 | 313 | # pcie led 314 | pcie_counter = Signal(32) 315 | self.sync.pcie += pcie_counter.eq(pcie_counter + 1) 316 | self.comb += self.pcie_led.eq(pcie_counter[26]) 317 | 318 | def generate_software_header(self): 319 | csr_header = get_csr_header(self.get_csr_regions(), 320 | self.get_constants(), 321 | with_access_functions=False) 322 | tools.write_to_file(os.path.join("software", "pcie", "kernel", "csr.h"), csr_header) 323 | 324 | class VideoSoC(BaseSoC): 325 | csr_peripherals = { 326 | "hdmi_out0", 327 | "hdmi_in0", 328 | "hdmi_in0_freq", 329 | "hdmi_in0_edid_mem" 330 | } 331 | csr_map_update(BaseSoC.csr_map, csr_peripherals) 332 | 333 | interrupt_map = { 334 | "hdmi_in0": 3, 335 | } 336 | interrupt_map.update(BaseSoC.interrupt_map) 337 | 338 | def __init__(self, platform, *args, **kwargs): 339 | BaseSoC.__init__(self, platform, *args, **kwargs) 340 | 341 | # # # 342 | 343 | pix_freq = 148.50e6 344 | 345 | # hdmi in 346 | hdmi_in0_pads = platform.request("hdmi_in") 347 | self.submodules.hdmi_in0_freq = FrequencyMeter(period=self.clk_freq) 348 | self.submodules.hdmi_in0 = HDMIIn(hdmi_in0_pads, 349 | self.sdram.crossbar.get_port(mode="write"), 350 | fifo_depth=512, 351 | device="xc7") 352 | self.comb += self.hdmi_in0_freq.clk.eq(self.hdmi_in0.clocking.cd_pix.clk) 353 | self.platform.add_period_constraint(self.hdmi_in0.clocking.cd_pix.clk, period_ns(1*pix_freq)) 354 | self.platform.add_period_constraint(self.hdmi_in0.clocking.cd_pix1p25x.clk, period_ns(1.25*pix_freq)) 355 | self.platform.add_period_constraint(self.hdmi_in0.clocking.cd_pix5x.clk, period_ns(5*pix_freq)) 356 | 357 | self.platform.add_false_path_constraints( 358 | self.crg.cd_sys.clk, 359 | self.hdmi_in0.clocking.cd_pix.clk, 360 | self.hdmi_in0.clocking.cd_pix1p25x.clk, 361 | self.hdmi_in0.clocking.cd_pix5x.clk) 362 | 363 | # hdmi out 364 | hdmi_out0_dram_port = self.sdram.crossbar.get_port(mode="read", dw=16, cd="hdmi_out0_pix", reverse=True) 365 | self.submodules.hdmi_out0 = VideoOut(platform.device, 366 | platform.request("hdmi_out"), 367 | hdmi_out0_dram_port, 368 | "ycbcr422", 369 | fifo_depth=4096) 370 | 371 | self.platform.add_period_constraint(self.hdmi_out0.driver.clocking.cd_pix.clk, period_ns(1*pix_freq)) 372 | self.platform.add_period_constraint(self.hdmi_out0.driver.clocking.cd_pix5x.clk, period_ns(5*pix_freq)) 373 | 374 | self.platform.add_false_path_constraints( 375 | self.crg.cd_sys.clk, 376 | self.hdmi_out0.driver.clocking.cd_pix.clk, 377 | self.hdmi_out0.driver.clocking.cd_pix5x.clk) 378 | 379 | # hdmi over 380 | self.comb += [ 381 | platform.request("hdmi_sda_over_up").eq(0), 382 | platform.request("hdmi_sda_over_dn").eq(0), 383 | platform.request("hdmi_hdp_over").eq(0), 384 | ] 385 | 386 | 387 | def main(): 388 | platform = Platform() 389 | if len(sys.argv) < 2: 390 | print("missing target (base or pcie or video)") 391 | exit() 392 | if sys.argv[1] == "base": 393 | soc = BaseSoC(platform) 394 | elif sys.argv[1] == "pcie": 395 | soc = PCIeSoC(platform) 396 | elif sys.argv[1] == "video": 397 | soc = VideoSoC(platform) 398 | builder = Builder(soc, output_dir="build", csr_csv="test/csr.csv") 399 | vns = builder.build() 400 | 401 | if sys.argv[1] == "pcie": 402 | soc.generate_software_header() 403 | 404 | if __name__ == "__main__": 405 | main() 406 | -------------------------------------------------------------------------------- /reverse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import os 4 | 5 | from litex.gen import * 6 | from litex.gen.genlib.resetsync import AsyncResetSynchronizer 7 | 8 | from litex.build.generic_platform import * 9 | from litex.build.xilinx import XilinxPlatform 10 | from litex.soc.cores import dna 11 | 12 | from litedram.modules import MT41J128M16 13 | from litedram.phy import a7ddrphy 14 | from litedram.core import ControllerSettings 15 | 16 | from litex.soc.integration.soc_core import * 17 | from litex.soc.integration.soc_sdram import * 18 | from litex.soc.integration.builder import * 19 | 20 | from litex.gen.genlib.cdc import MultiReg 21 | 22 | 23 | _io = [ 24 | ("clk50", 0, Pins("J19"), IOStandard("LVCMOS33")), 25 | 26 | ("user_led", 0, Pins("M21"), IOStandard("LVCMOS33")), 27 | ("user_led", 1, Pins("N20"), IOStandard("LVCMOS33")), 28 | ("user_led", 2, Pins("L21"), IOStandard("LVCMOS33")), 29 | 30 | ("serial", 0, 31 | Subsignal("tx", Pins("E14")), 32 | Subsignal("rx", Pins("E13")), 33 | IOStandard("LVCMOS33"), 34 | ), 35 | 36 | ("serial_litescope", 0, 37 | Subsignal("tx", Pins("C18")), # hax 10 38 | Subsignal("rx", Pins("B20")), # hax 12 39 | IOStandard("LVCMOS33") 40 | ), 41 | 42 | ("ddram", 0, 43 | Subsignal("a", Pins( 44 | "U6 V4 W5 V5 AA1 Y2 AB1 AB3", 45 | "AB2 Y3 W6 Y1 V2 AA3" 46 | ), 47 | IOStandard("SSTL15")), 48 | Subsignal("ba", Pins("U5 W4 V7"), IOStandard("SSTL15")), 49 | Subsignal("ras_n", Pins("Y9"), IOStandard("SSTL15")), 50 | Subsignal("cas_n", Pins("Y7"), IOStandard("SSTL15")), 51 | Subsignal("we_n", Pins("V8"), IOStandard("SSTL15")), 52 | Subsignal("dm", Pins("G1 H4 M5 L3"), IOStandard("SSTL15")), 53 | Subsignal("dq", Pins( 54 | "C2 F1 B1 F3 A1 D2 B2 E2 " 55 | "J5 H3 K1 H2 J1 G2 H5 G3 " 56 | "N2 M6 P1 N5 P2 N4 R1 P6 " 57 | "K3 M2 K4 M3 J6 L5 J4 K6 " 58 | ), 59 | IOStandard("SSTL15"), 60 | Misc("IN_TERM=UNTUNED_SPLIT_50")), 61 | Subsignal("dqs_p", Pins("E1 K2 P5 M1"), IOStandard("DIFF_SSTL15")), 62 | Subsignal("dqs_n", Pins("D1 J2 P4 L1"), IOStandard("DIFF_SSTL15")), 63 | Subsignal("clk_p", Pins("R3"), IOStandard("DIFF_SSTL15")), 64 | Subsignal("clk_n", Pins("R2"), IOStandard("DIFF_SSTL15")), 65 | Subsignal("cke", Pins("Y8"), IOStandard("SSTL15")), 66 | Subsignal("odt", Pins("W9"), IOStandard("SSTL15")), 67 | Subsignal("reset_n", Pins("AB5"), IOStandard("LVCMOS15")), 68 | Subsignal("cs_n", Pins("V9"), IOStandard("SSTL15")), 69 | Misc("SLEW=FAST"), 70 | ), 71 | ] 72 | 73 | class Platform(XilinxPlatform): 74 | def __init__(self, toolchain="vivado", programmer="vivado"): 75 | XilinxPlatform.__init__(self, "xc7a35t-fgg484-2", _io, 76 | toolchain=toolchain) 77 | 78 | self.add_platform_command( 79 | "set_property CONFIG_VOLTAGE 3.3 [current_design]") 80 | self.add_platform_command( 81 | "set_property CFGBVS VCCO [current_design]") 82 | self.add_platform_command( 83 | "set_property BITSTREAM.CONFIG.CONFIGRATE 22 [current_design]") 84 | self.add_platform_command( 85 | "set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]") 86 | self.toolchain.bitstream_commands = [ 87 | "set_property CONFIG_VOLTAGE 1.5 [current_design]", 88 | "set_property CFGBVS GND [current_design]", 89 | "set_property BITSTREAM.CONFIG.CONFIGRATE 22 [current_design]", 90 | "set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 1 [current_design]", 91 | ] 92 | self.toolchain.additional_commands = \ 93 | ["write_cfgmem -verbose -force -format bin -interface spix1 -size 64 " 94 | "-loadbit \"up 0x0 {build_name}.bit\" -file {build_name}.bin"] 95 | self.programmer = programmer 96 | 97 | self.add_platform_command(""" 98 | create_clock -name pcie_phy_clk -period 10.0 [get_pins {{pcie_phy/pcie_support_i/pcie_i/inst/inst/gt_top_i/pipe_wrapper_i/pipe_lane[0].gt_wrapper_i/gtp_channel.gtpe2_channel_i/TXOUTCLK}}] 99 | """) 100 | 101 | def create_programmer(self): 102 | if self.programmer == "vivado": 103 | return VivadoProgrammer(flash_part="n25q128-3.3v-spi-x1_x2_x4") 104 | else: 105 | raise ValueError("{} programmer is not supported" 106 | .format(self.programmer)) 107 | 108 | def do_finalize(self, fragment): 109 | XilinxPlatform.do_finalize(self, fragment) 110 | 111 | 112 | def csr_map_update(csr_map, csr_peripherals): 113 | csr_map.update(dict((n, v) 114 | for v, n in enumerate(csr_peripherals, start=max(csr_map.values()) + 1))) 115 | 116 | 117 | def period_ns(freq): 118 | return 1e9/freq 119 | 120 | 121 | class CRG(Module): 122 | def __init__(self, platform): 123 | self.clock_domains.cd_sys = ClockDomain() 124 | self.clock_domains.cd_sys4x = ClockDomain(reset_less=True) 125 | self.clock_domains.cd_sys4x_dqs = ClockDomain(reset_less=True) 126 | self.clock_domains.cd_clk200 = ClockDomain() 127 | self.clock_domains.cd_clk100 = ClockDomain() 128 | 129 | clk50 = platform.request("clk50") 130 | rst = Signal() 131 | 132 | pll_locked = Signal() 133 | pll_fb = Signal() 134 | self.pll_sys = Signal() 135 | pll_sys4x = Signal() 136 | pll_sys4x_dqs = Signal() 137 | pll_clk200 = Signal() 138 | self.specials += [ 139 | Instance("PLLE2_BASE", 140 | p_STARTUP_WAIT="FALSE", o_LOCKED=pll_locked, 141 | 142 | # VCO @ 1600 MHz 143 | p_REF_JITTER1=0.01, p_CLKIN1_PERIOD=20.0, 144 | p_CLKFBOUT_MULT=32, p_DIVCLK_DIVIDE=1, 145 | i_CLKIN1=clk50, i_CLKFBIN=pll_fb, o_CLKFBOUT=pll_fb, 146 | 147 | # 100 MHz 148 | p_CLKOUT0_DIVIDE=16, p_CLKOUT0_PHASE=0.0, 149 | o_CLKOUT0=self.pll_sys, 150 | 151 | # 400 MHz 152 | p_CLKOUT1_DIVIDE=4, p_CLKOUT1_PHASE=0.0, 153 | o_CLKOUT1=pll_sys4x, 154 | 155 | # 400 MHz dqs 156 | p_CLKOUT2_DIVIDE=4, p_CLKOUT2_PHASE=90.0, 157 | o_CLKOUT2=pll_sys4x_dqs, 158 | 159 | # 200 MHz 160 | p_CLKOUT3_DIVIDE=8, p_CLKOUT3_PHASE=0.0, 161 | o_CLKOUT3=pll_clk200 162 | ), 163 | Instance("BUFG", i_I=self.pll_sys, o_O=self.cd_sys.clk), 164 | Instance("BUFG", i_I=self.pll_sys, o_O=self.cd_clk100.clk), 165 | Instance("BUFG", i_I=pll_clk200, o_O=self.cd_clk200.clk), 166 | Instance("BUFG", i_I=pll_sys4x, o_O=self.cd_sys4x.clk), 167 | Instance("BUFG", i_I=pll_sys4x_dqs, o_O=self.cd_sys4x_dqs.clk), 168 | AsyncResetSynchronizer(self.cd_sys, ~pll_locked | rst), 169 | AsyncResetSynchronizer(self.cd_clk200, ~pll_locked | rst), 170 | AsyncResetSynchronizer(self.cd_clk100, ~pll_locked | rst) 171 | ] 172 | 173 | reset_counter = Signal(4, reset=15) 174 | ic_reset = Signal(reset=1) 175 | self.sync.clk200 += \ 176 | If(reset_counter != 0, 177 | reset_counter.eq(reset_counter - 1) 178 | ).Else( 179 | ic_reset.eq(0) 180 | ) 181 | self.specials += Instance("IDELAYCTRL", i_REFCLK=ClockSignal("clk200"), i_RST=ic_reset) 182 | 183 | # Module that turns an LED on and off at some interval (`period` clock cycles), 184 | # with a specific on time (`width` clock cycles). 185 | # i.e. `width/period` is the PWM duty cycle, and `1/period` is the PWM frequency. 186 | # ________ ________ 187 | # ___| |_____________________| |_____________________ 188 | # <-width-> 189 | # <------------period-----------> 190 | class BlinkerPwm(Module): 191 | def __init__(self, led, width, period): 192 | # Create a counter to track where we are in the pulse. 193 | counter = Signal(max=period) 194 | 195 | self.comb += [ 196 | # On until we get to `width` 197 | If(counter < width, 198 | led.eq(1) 199 | ).Else( 200 | led.eq(0) 201 | ), 202 | ] 203 | self.sync += [ 204 | If(counter == period - 1, 205 | # Reset the counter when we get to `period-1` 206 | counter.eq(0) 207 | ).Else( 208 | # Otherwise increment the counter. 209 | counter.eq(counter + 1) 210 | ) 211 | ] 212 | 213 | # Module that pulses an LED by ramping up and down its brightness, but 214 | # re-using the PWM module for brightness. 215 | # Every `cycles` clock cycles, the PWM width is inc/decreased/ from 216 | # 0% to 100%. 217 | class BlinkerBreathe(BlinkerPwm): 218 | def __init__(self, led, period, cycles): 219 | width = Signal(max=period) 220 | direction = Signal() 221 | super().__init__(led, width, period) 222 | # Create a counter to track cycles until we increment brightness. 223 | counter = Signal(max=cycles) 224 | 225 | self.sync += [ 226 | # Inc/decrement the brightness. 227 | If((counter == 0) & (direction == 0), 228 | width.eq(width + 1) 229 | ).Elif((counter == 0) & (direction == 1), 230 | width.eq(width - 1) 231 | ), 232 | If(counter == 0, 233 | # Start counting backwards from `cycles` again. 234 | counter.eq(cycles - 1) 235 | ).Else( 236 | # Keep counting backwards... 237 | counter.eq(counter - 1) 238 | ), 239 | # Toggle the direction at each end. 240 | If((direction == 0) & (width == period - 1), 241 | direction.eq(1) 242 | ).Elif((direction == 1) & (width == 0), 243 | direction.eq(0) 244 | ) 245 | ] 246 | 247 | class Flintstone(Module): 248 | def __init__(self): 249 | self.wilma = Signal(16) 250 | 251 | self.sync += [ 252 | If( self.wilma >= 65535, 253 | self.wilma.eq(0) 254 | ).Else( 255 | self.wilma.eq(self.wilma + 6502) 256 | ) 257 | ] 258 | 259 | class SimpleSync(Module): 260 | def __init__(self, d, q): 261 | self.sync += [ 262 | q.eq(d) 263 | ] 264 | 265 | #questions to resolve: 266 | # signals that are smaller than expected -- alignment? 267 | ### answer: it passes the ambguity directly down to verilog :P 268 | # if b is 8 bits and a is 16 bits, 269 | # b = a gets the LSBs of a, e.g. b = a[7:0] if you do b = a 270 | # if b is 32 bits and 1 as 16 bits, 271 | # b = a zero-extends a, eg. b[15:0] = a[15:0] and b[31:16] = 16'b0 272 | 273 | # cross-domain clocks 274 | 275 | class MicroSoC(SoCCore): 276 | def __init__(self, platform, **kwargs): 277 | 278 | clk_freq = int(100e6) 279 | SoCCore.__init__(self, platform, clk_freq, 280 | cpu_type=None, 281 | **kwargs) 282 | 283 | self.platform = platform 284 | 285 | self.submodules.crg = CRG(platform) 286 | self.crg.cd_sys.clk.attr.add("keep") 287 | self.platform.add_period_constraint(self.crg.cd_sys.clk, period_ns(100e6)) 288 | 289 | # common led 290 | self.sys_led = Signal() 291 | self.comb += platform.request("user_led", 0).eq(self.sys_led) 292 | 293 | self.aux_led = Signal() 294 | self.comb += platform.request("user_led", 1).eq(self.aux_led) 295 | 296 | # sys led 297 | sys_counter = Signal(32) 298 | self.sync += sys_counter.eq(sys_counter + 1) 299 | self.comb += self.sys_led.eq(sys_counter[26]) 300 | 301 | sys_short_test = Signal(16) 302 | self.comb += sys_short_test.eq(sys_counter) 303 | self.comb += self.aux_led.eq(sys_short_test[15]) 304 | 305 | self.bar_led = platform.request("user_led", 2) 306 | 307 | fred = ClockDomainsRenamer("clk100")(Flintstone()) 308 | self.submodules += fred ## if this isn't here, fred isn't instantiated 309 | 310 | self.dino = Signal(16) 311 | self.yoshi = Signal(8) 312 | self.specials += MultiReg(fred.wilma, self.dino, "clk100") 313 | self.specials += MultiReg(self.dino, self.yoshi, "clk200") # this takes dino into the yoshi clock domain 314 | self.comb += self.bar_led.eq(self.yoshi[7]) 315 | 316 | # what I'm expecting: 317 | # Fred() makes a counter (called wilma) in the always@clk100 domain 318 | # The instance is called barney. 319 | # Barney's wilma gets retimed into clk200 as the name "dino" 320 | # bar_led gets dino[15] 321 | 322 | # what I'm getting: 323 | # wilma is a clk100 counter. 324 | # her output is "retimed" into the clk100 domain through two DFF stages and dumped into dino 325 | # dino is retimed into the clk200 domain via two DFFs 326 | # yoshi is LSB-aligned to dino 327 | # user_led 2 gets yoshi[7] which is dino[7] 328 | 329 | 330 | # So: ClockDomainsRenamer(domain1)(function1) takes everything inside function1() and puts it in clock domain domain1 331 | # MultiReg(a, b, domain2) takes the signals on b, assigns them to a, retiming into domain2 332 | 333 | 334 | 335 | 336 | 337 | class MinSoC(SoCCore): 338 | csr_peripherals = { 339 | "dna", 340 | } 341 | 342 | csr_map_update(SoCCore.csr_map, csr_peripherals) 343 | 344 | def __init__(self, platform, **kwargs): 345 | clk_freq = int(100e6) 346 | SoCCore.__init__(self, platform, clk_freq, 347 | integrated_rom_size=0x6000, 348 | integrated_sram_size=0x4000, 349 | ident="NeTV2 minimum SoC core", 350 | reserve_nmi_interrupt=False, 351 | **kwargs) 352 | 353 | self.submodules.crg = CRG(platform) 354 | self.submodules.dna = dna.DNA() 355 | 356 | self.crg.cd_sys.clk.attr.add("keep") 357 | self.platform.add_period_constraint(self.crg.cd_sys.clk, period_ns(100e6)) 358 | 359 | # common led 360 | self.sys_led = Signal() 361 | self.comb += platform.request("user_led", 0).eq(self.sys_led) 362 | 363 | # sys led 364 | sys_counter = Signal(32) 365 | self.sync += sys_counter.eq(sys_counter + 1) 366 | self.comb += self.sys_led.eq(sys_counter[26]) 367 | 368 | 369 | class BaseSoC(SoCSDRAM): 370 | csr_peripherals = { 371 | "ddrphy", 372 | "dna", 373 | } 374 | csr_map_update(SoCSDRAM.csr_map, csr_peripherals) 375 | 376 | def __init__(self, platform, **kwargs): 377 | clk_freq = int(100e6) 378 | SoCSDRAM.__init__(self, platform, clk_freq, 379 | integrated_rom_size=0x6000, 380 | integrated_sram_size=0x4000, 381 | #shadow_base=0x00000000, 382 | ident="NeTV2 LiteX Reversing SoC", 383 | reserve_nmi_interrupt=False, 384 | **kwargs) 385 | 386 | self.submodules.crg = CRG(platform) 387 | self.submodules.dna = dna.DNA() 388 | 389 | self.crg.cd_sys.clk.attr.add("keep") 390 | self.platform.add_period_constraint(self.crg.cd_sys.clk, period_ns(100e6)) 391 | 392 | # sdram 393 | self.submodules.ddrphy = a7ddrphy.A7DDRPHY(platform.request("ddram")) 394 | sdram_module = MT41J128M16(self.clk_freq, "1:4") 395 | self.add_constant("READ_LEVELING_BITSLIP", 3) 396 | self.add_constant("READ_LEVELING_DELAY", 14) 397 | self.register_sdram(self.ddrphy, 398 | sdram_module.geom_settings, 399 | sdram_module.timing_settings, 400 | controller_settings=ControllerSettings(with_bandwidth=True, 401 | cmd_buffer_depth=8, 402 | with_refresh=False)) 403 | 404 | # common led 405 | self.sys_led = Signal() 406 | self.pcie_led = Signal() 407 | self.comb += platform.request("user_led", 0).eq(self.sys_led ^ self.pcie_led) 408 | 409 | # sys led 410 | sys_counter = Signal(32) 411 | self.sync += sys_counter.eq(sys_counter + 1) 412 | self.comb += self.sys_led.eq(sys_counter[26]) 413 | 414 | class ReverseSoC(BaseSoC): 415 | csr_peripherals = { 416 | "analyzer" 417 | } 418 | csr_map_update(BaseSoC.csr_map, csr_peripherals) 419 | 420 | # interrupt_map = { 421 | # "hdmi_in0": 3, 422 | # } 423 | # interrupt_map.update(BaseSoC.interrupt_map) 424 | 425 | def __init__(self, platform, *args, **kwargs): 426 | BaseSoC.__init__(self, platform, *args, **kwargs) 427 | 428 | # # # 429 | 430 | pix_freq = 148.50e6 431 | 432 | # analyzer 433 | from litex.soc.cores.uart import UARTWishboneBridge 434 | from litescope import LiteScopeAnalyzer 435 | 436 | self.submodules.bridge = UARTWishboneBridge( 437 | platform.request("serial_litescope"), self.clk_freq, baudrate=115200) 438 | self.add_wb_master(self.bridge.wishbone) 439 | 440 | analyzer_signals = [ 441 | self.sys_led, 442 | ] 443 | self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals, 2048, cd="clk200", cd_ratio=2) 444 | 445 | def do_exit(self, vns): 446 | self.analyzer.export_csv(vns, "test/analyzer.csv") 447 | 448 | def main(): 449 | platform = Platform() 450 | if len(sys.argv) < 2: 451 | print("missing target (base or pcie or video or video_raw_loopback or video_raw_dma_loopback)") 452 | exit() 453 | if sys.argv[1] == "base": 454 | soc = BaseSoC(platform) 455 | elif sys.argv[1] == "reverse": 456 | soc = ReverseSoC(platform) 457 | elif sys.argv[1] == "min": 458 | soc = MinSoC(platform) 459 | elif sys.argv[1] == "micro": 460 | soc=MicroSoC(platform) 461 | 462 | if sys.argv[1] == "micro": 463 | soc.cpu_type=None 464 | builder = Builder(soc, output_dir="build") 465 | else: 466 | builder = Builder(soc, output_dir="build", csr_csv="test/csr.csv") 467 | 468 | vns = builder.build() 469 | soc.do_exit(vns) 470 | 471 | if sys.argv[1] == "pcie": 472 | soc.generate_software_header() 473 | 474 | if __name__ == "__main__": 475 | main() 476 | -------------------------------------------------------------------------------- /firmware/processor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "stdio_wrap.h" 5 | 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include "hdmi_in0.h" 12 | #include "hdmi_in1.h" 13 | #include "pattern.h" 14 | #include "encoder.h" 15 | #include "edid.h" 16 | #include "mmcm.h" 17 | #include "processor.h" 18 | 19 | /* 20 | ----------------->>> Time ----------->>> 21 | 22 | +-------------------+ 23 | Video | Blanking | Video 24 | | | 25 | ----(a)--------->|<-------(b)------->| 26 | | | 27 | | +-------+ | 28 | | | Sync | | 29 | | | | | 30 | |<-(c)->|<-(d)->| | 31 | | | | | 32 | ----(1)--------->| | | | 33 | ----(2)----------------->| | | 34 | ----(3)------------------------->| | 35 | ----(4)----------------------------->| 36 | | | | | 37 | 38 | (a) - h_active ==(1) 39 | (b) - h_blanking 40 | (c) - h_sync_offset 41 | (d) - h_sync_width 42 | (1) - HDisp / width == (a) 43 | (2) - HSyncStart 44 | (3) - HSyncEnd 45 | (4) - HTotal 46 | 47 | Modeline "String description" Dot-Clock HDisp HSyncStart HSyncEnd HTotal VDisp VSyncStart VSyncEnd VTotal [options] 48 | 49 | (1|a) (2) (3) (4) 50 | ModeLine "640x480" 31.5 640 664 704 832 480 489 491 520 51 | |\-(c)-/\-(d)-/ | 52 | | 24 40 | 53 | | | 54 | \--------(b)-------/ 55 | 192 56 | 57 | References: 58 | * http://www.arachnoid.com/modelines/ 59 | * http://martin.hinner.info/vga/timing.html 60 | * VESA Modes - http://cvsweb.xfree86.org/cvsweb/xc/programs/Xserver/hw/xfree86/etc/vesamodes 61 | * 720p and TV modes - https://www.mythtv.org/wiki/Modeline_Database 62 | 63 | */ 64 | const struct video_timing video_modes[PROCESSOR_MODE_COUNT] = { 65 | // 640x480 @ 72Hz (VESA) hsync: 37.9kHz 66 | // ModeLine "640x480" 31.5 640 664 704 832 480 489 491 520 67 | // 24 40 <192 9 2 <40 68 | { 69 | .pixel_clock = 3150, 70 | 71 | .h_active = 640, 72 | .h_blanking = 192, 73 | .h_sync_offset = 24, 74 | .h_sync_width = 40, 75 | 76 | .v_active = 480, 77 | .v_blanking = 40, 78 | .v_sync_offset = 9, 79 | .v_sync_width = 3, 80 | 81 | .established_timing = 0x0800 82 | }, 83 | // 640x480 @ 75Hz (VESA) hsync: 37.5kHz 84 | // ModeLine "640x480" 31.5 640 656 720 840 480 481 484 500 85 | // 16 64 <200 1 3 <20 86 | { 87 | .pixel_clock = 3150, 88 | 89 | .h_active = 640, 90 | .h_blanking = 200, 91 | .h_sync_offset = 16, 92 | .h_sync_width = 64, 93 | 94 | .v_active = 480, 95 | .v_blanking = 20, 96 | .v_sync_offset = 1, 97 | .v_sync_width = 3, 98 | 99 | .established_timing = 0x0400 100 | }, 101 | // 800x600 @ 56Hz (VESA) hsync: 35.2kHz 102 | // ModeLine "800x600" 36.0 800 824 896 1024 600 601 603 625 103 | { 104 | .pixel_clock = 3600, 105 | 106 | .h_active = 800, 107 | .h_blanking = 224, 108 | .h_sync_offset = 24, 109 | .h_sync_width = 72, 110 | 111 | .v_active = 600, 112 | .v_blanking = 25, 113 | .v_sync_offset = 1, 114 | .v_sync_width = 2, 115 | 116 | .established_timing = 0x0200 117 | }, 118 | // 800x600 @ 60Hz (VESA) hsync: 37.9kHz 119 | // ModeLine "800x600" 40.0 800 840 968 1056 600 601 605 628 120 | { 121 | .pixel_clock = 4000, 122 | 123 | .h_active = 800, 124 | .h_blanking = 256, 125 | .h_sync_offset = 40, 126 | .h_sync_width = 128, 127 | 128 | .v_active = 600, 129 | .v_blanking = 28, 130 | .v_sync_offset = 1, 131 | .v_sync_width = 4, 132 | 133 | .established_timing = 0x0100 134 | }, 135 | // 800x600 @ 72Hz (VESA) hsync: 48.1kHz 136 | // ModeLine "800x600" 50.0 800 856 976 1040 600 637 643 666 137 | { 138 | .pixel_clock = 5000, 139 | 140 | .h_active = 800, 141 | .h_blanking = 240, 142 | .h_sync_offset = 56, 143 | .h_sync_width = 120, 144 | 145 | .v_active = 600, 146 | .v_blanking = 66, 147 | .v_sync_offset = 37, 148 | .v_sync_width = 6, 149 | 150 | .established_timing = 0x0080 151 | }, 152 | // 800x600 @ 75Hz (VESA) hsync: 46.9kHz 153 | // ModeLine "800x600" 49.5 800 816 896 1056 600 601 604 625 154 | { 155 | .pixel_clock = 4950, 156 | 157 | .h_active = 800, 158 | .h_blanking = 256, 159 | .h_sync_offset = 16, 160 | .h_sync_width = 80, 161 | 162 | .v_active = 600, 163 | .v_blanking = 25, 164 | .v_sync_offset = 1, 165 | .v_sync_width = 3, 166 | 167 | .established_timing = 0x0040 168 | }, 169 | // 1024x768 @ 60Hz (VESA) hsync: 48.4kHz 170 | // ModeLine "1024x768" 65.0 1024 1048 1184 1344 768 771 777 806 171 | { 172 | .pixel_clock = 6500, 173 | 174 | .h_active = 1024, 175 | .h_blanking = 320, 176 | .h_sync_offset = 24, 177 | .h_sync_width = 136, 178 | 179 | .v_active = 768, 180 | .v_blanking = 38, 181 | .v_sync_offset = 3, 182 | .v_sync_width = 6, 183 | 184 | .established_timing = 0x0008 185 | }, 186 | // 1024x768 @ 70Hz (VESA) hsync: 56.5kHz 187 | // ModeLine "1024x768" 75.0 1024 1048 1184 1328 768 771 777 806 188 | { 189 | .pixel_clock = 7500, 190 | 191 | .h_active = 1024, 192 | .h_blanking = 304, 193 | .h_sync_offset = 24, 194 | .h_sync_width = 136, 195 | 196 | .v_active = 768, 197 | .v_blanking = 38, 198 | .v_sync_offset = 3, 199 | .v_sync_width = 6, 200 | 201 | .established_timing = 0x0004 202 | }, 203 | // 1024x768 @ 75Hz (VESA) hsync: 60.0kHz 204 | // ModeLine "1024x768" 78.8 1024 1040 1136 1312 768 769 772 800 205 | { 206 | .pixel_clock = 7880, 207 | 208 | .h_active = 1024, 209 | .h_blanking = 288, 210 | .h_sync_offset = 16, 211 | .h_sync_width = 96, 212 | 213 | .v_active = 768, 214 | .v_blanking = 32, 215 | .v_sync_offset = 1, 216 | .v_sync_width = 3, 217 | 218 | .established_timing = 0x0002 219 | }, 220 | // 720p @ 60Hz 221 | //1280 720 60 Hz 45 kHz ModeLine "1280x720" 74.25 1280 1390 1430 1650 720 725 730 750 +HSync +VSync 222 | { 223 | .pixel_clock = 7425, 224 | 225 | .h_active = 1280, 226 | .h_blanking = 370, 227 | .h_sync_offset = 220, 228 | .h_sync_width = 40, 229 | 230 | .v_active = 720, 231 | .v_blanking = 30, 232 | .v_sync_offset = 20, 233 | .v_sync_width = 5 234 | }, 235 | // Other 720p60 modes not enabled... 236 | //1280 720 60 Hz 44.9576 kHz ModeLine "1280x720" 74.18 1280 1390 1430 1650 720 725 730 750 +HSync +VSync 237 | //1280 720 59.94 ModeLine "ATSC-720-59.94p" 74.176 1280 1320 1376 1650 720 722 728 750 238 | //1280 720 60 Hz ModeLine "ATSC-720-60p" 74.25 1280 1320 1376 1650 720 722 728 750 239 | 240 | // 720p @ 50Hz 241 | // 19 720p50 16:9 1:1 1280x720p @ 50 Hz 242 | //1280 720 50 Hz 37.5 kHz ModeLine "1280x720" 74.25 1280 1720 1760 1980 720 725 730 750 +HSync +VSync 243 | // 440 40 <700 5 5 <30 244 | { 245 | .pixel_clock = 7425, 246 | 247 | .h_active = 1280, 248 | .h_blanking = 700, 249 | .h_sync_offset = 440, 250 | .h_sync_width = 40, 251 | 252 | .v_active = 720, 253 | .v_blanking = 30, 254 | .v_sync_offset = 5, 255 | .v_sync_width = 5 256 | }, 257 | // 1920x1080 @ 60.00 Hz Modeline: "1920x1080" 148.500 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync 258 | { 259 | .pixel_clock = 14850, 260 | 261 | .h_active = 1920, 262 | .h_blanking = 280, 263 | .h_sync_offset = 88, 264 | .h_sync_width = 44, 265 | 266 | .v_active = 1080, 267 | .v_blanking = 45, 268 | .v_sync_offset = 4, 269 | .v_sync_width = 5 270 | }, 271 | // "fake" 1920x1080 @ 60.00 Hz Modeline: "1920x1080" 148.500 1920 2008 2052 2200 1080 1084 1089 1125 +hsync +vsync 272 | { 273 | .pixel_clock = 7425, 274 | 275 | .h_active = 1920, 276 | .h_blanking = 280, 277 | .h_sync_offset = 88, 278 | .h_sync_width = 44, 279 | 280 | .v_active = 1080, 281 | .v_blanking = 45, 282 | .v_sync_offset = 4, 283 | .v_sync_width = 5 284 | }, 285 | // 720x480 @ 60.00 Hz Modeline "720x480" 26.72 720 736 808 896 480 481 484 497 -HSync +Vsync 286 | { 287 | .pixel_clock = 2672, 288 | 289 | .h_active = 720, 290 | .h_blanking = 176, 291 | .h_sync_offset = 16, 292 | .h_sync_width = 72, 293 | 294 | .v_active = 480, 295 | .v_blanking = 17, 296 | .v_sync_offset = 1, 297 | .v_sync_width = 3, 298 | .comment = "(HV20/HV30 in NTSC mode)" 299 | }, 300 | // 720x576 @ 50.00 Hz Modeline 720x576" 32.67 720 744 816 912 576 577 580 597 -HSync +Vsyncc 301 | { 302 | .pixel_clock = 3267, 303 | 304 | .h_active = 720, 305 | .h_blanking = 192, 306 | .h_sync_offset = 24, 307 | .h_sync_width = 72, 308 | 309 | .v_active = 576, 310 | .v_blanking = 21, 311 | .v_sync_offset = 1, 312 | .v_sync_width = 3, 313 | .comment = "(HV20/HV30 in PAL mode)" 314 | } 315 | 316 | }; 317 | 318 | void processor_list_modes(char *mode_descriptors) 319 | { 320 | int i; 321 | for(i=0;ipixel_clock), &clock_m, &clock_d); 386 | 387 | #ifdef CSR_HDMI_OUT0_BASE 388 | unsigned int hdmi_out0_enabled; 389 | if (hdmi_out0_core_initiator_enable_read()) { 390 | hdmi_out0_enabled = 1; 391 | hdmi_out0_core_initiator_enable_write(0); 392 | } 393 | hdmi_out0_core_initiator_hres_write(mode->h_active); 394 | hdmi_out0_core_initiator_hsync_start_write(mode->h_active + mode->h_sync_offset); 395 | hdmi_out0_core_initiator_hsync_end_write(mode->h_active + mode->h_sync_offset + mode->h_sync_width); 396 | hdmi_out0_core_initiator_hscan_write(mode->h_active + mode->h_blanking); 397 | hdmi_out0_core_initiator_vres_write(mode->v_active); 398 | hdmi_out0_core_initiator_vsync_start_write(mode->v_active + mode->v_sync_offset); 399 | hdmi_out0_core_initiator_vsync_end_write(mode->v_active + mode->v_sync_offset + mode->v_sync_width); 400 | hdmi_out0_core_initiator_vscan_write(mode->v_active + mode->v_blanking); 401 | 402 | hdmi_out0_core_initiator_length_write(mode->h_active*mode->v_active*2); 403 | 404 | hdmi_out0_core_initiator_enable_write(hdmi_out0_enabled); 405 | #endif 406 | 407 | #ifdef CSR_HDMI_OUT1_BASE 408 | unsigned int hdmi_out1_enabled; 409 | if (hdmi_out1_core_initiator_enable_read()) { 410 | hdmi_out1_enabled = 1; 411 | hdmi_out1_core_initiator_enable_write(0); 412 | } 413 | hdmi_out1_core_initiator_hres_write(mode->h_active); 414 | hdmi_out1_core_initiator_hsync_start_write(mode->h_active + mode->h_sync_offset); 415 | hdmi_out1_core_initiator_hsync_end_write(mode->h_active + mode->h_sync_offset + mode->h_sync_width); 416 | hdmi_out1_core_initiator_hscan_write(mode->h_active + mode->h_blanking); 417 | hdmi_out1_core_initiator_vres_write(mode->v_active); 418 | hdmi_out1_core_initiator_vsync_start_write(mode->v_active + mode->v_sync_offset); 419 | hdmi_out1_core_initiator_vsync_end_write(mode->v_active + mode->v_sync_offset + mode->v_sync_width); 420 | hdmi_out1_core_initiator_vscan_write(mode->v_active + mode->v_blanking); 421 | 422 | hdmi_out1_core_initiator_length_write(mode->h_active*mode->v_active*2); 423 | 424 | hdmi_out1_core_initiator_enable_write(hdmi_out1_enabled); 425 | #endif 426 | 427 | fb_clkgen_write(clock_m, clock_d); 428 | } 429 | 430 | static void edid_set_mode(const struct video_timing *mode) 431 | { 432 | #if defined(CSR_HDMI_IN0_BASE) || defined(CSR_HDMI_IN1_BASE) 433 | unsigned char edid[128]; 434 | int i; 435 | #endif 436 | #ifdef CSR_HDMI_IN0_BASE 437 | generate_edid(&edid, "OHW", "TV", 2015, "HDMI2USB 1", mode); 438 | for(i=0;ih_active; 467 | processor_v_active = m->v_active; 468 | processor_refresh = calculate_refresh_rate(m); 469 | 470 | #ifdef CSR_HDMI_OUT0_BASE 471 | hdmi_out0_core_initiator_enable_write(0); 472 | hdmi_out0_driver_clocking_mmcm_reset_write(1); 473 | #endif 474 | #ifdef CSR_HDMI_OUT1_BASE 475 | hdmi_out1_core_initiator_enable_write(0); 476 | #endif 477 | #ifdef CSR_HDMI_IN0_BASE 478 | hdmi_in0_edid_hpd_en_write(0); 479 | #endif 480 | #ifdef CSR_HDMI_IN1_BASE 481 | hdmi_in1_edid_hpd_en_write(0); 482 | #endif 483 | 484 | #ifdef CSR_HDMI_IN0_BASE 485 | hdmi_in0_disable(); 486 | hdmi_in0_clear_framebuffers(); 487 | #endif 488 | #ifdef CSR_HDMI_IN1_BASE 489 | hdmi_in1_disable(); 490 | hdmi_in1_clear_framebuffers(); 491 | #endif 492 | #ifndef SIMULATION 493 | pattern_fill_framebuffer(m->h_active, m->v_active); 494 | #endif 495 | 496 | printf("."); 497 | #ifdef CSR_HDMI_IN0_BASE 498 | mmcm_config_for_clock(m->pixel_clock); 499 | #endif 500 | printf("."); 501 | fb_set_mode(m); 502 | edid_set_mode(m); 503 | #ifdef CSR_HDMI_IN0_BASE 504 | hdmi_in0_init_video(m->h_active, m->v_active); 505 | #endif 506 | #ifdef CSR_HDMI_IN1_BASE 507 | hdmi_in1_init_video(m->h_active, m->v_active); 508 | #endif 509 | 510 | #ifdef CSR_HDMI_OUT0_BASE 511 | hdmi_out0_driver_clocking_mmcm_reset_write(0); 512 | hdmi_out0_core_initiator_enable_write(1); 513 | #endif 514 | #ifdef CSR_HDMI_OUT1_BASE 515 | hdmi_out1_core_initiator_enable_write(1); 516 | #endif 517 | #ifdef CSR_HDMI_IN0_BASE 518 | hdmi_in0_edid_hpd_en_write(1); 519 | #endif 520 | #ifdef CSR_HDMI_IN1_BASE 521 | hdmi_in1_edid_hpd_en_write(1); 522 | #endif 523 | 524 | } 525 | 526 | void processor_set_hdmi_out0_source(int source) { 527 | processor_hdmi_out0_source = source; 528 | } 529 | 530 | void processor_set_hdmi_out1_source(int source) { 531 | processor_hdmi_out1_source = source; 532 | } 533 | 534 | void processor_set_encoder_source(int source) { 535 | processor_encoder_source = source; 536 | } 537 | 538 | char * processor_get_source_name(int source) { 539 | memset(processor_buffer, 0, 16); 540 | if(source == VIDEO_IN_PATTERN) 541 | sprintf(processor_buffer, "pattern"); 542 | else 543 | sprintf(processor_buffer, "input%d", source); 544 | return processor_buffer; 545 | } 546 | 547 | void processor_update(void) 548 | { 549 | 550 | #ifdef CSR_HDMI_OUT0_BASE 551 | /* hdmi_out0 */ 552 | #ifdef CSR_HDMI_IN0_BASE 553 | if(processor_hdmi_out0_source == VIDEO_IN_HDMI_IN0) 554 | hdmi_out0_core_initiator_base_write(hdmi_in0_framebuffer_base(hdmi_in0_fb_index)); 555 | #endif 556 | #ifdef CSR_HDMI_IN1_BASE 557 | if(processor_hdmi_out0_source == VIDEO_IN_HDMI_IN1) 558 | hdmi_out0_core_initiator_base_write(hdmi_in1_framebuffer_base(hdmi_in1_fb_index)); 559 | #endif 560 | if(processor_hdmi_out0_source == VIDEO_IN_PATTERN) 561 | hdmi_out0_core_initiator_base_write(pattern_framebuffer_base()); 562 | #endif 563 | 564 | #ifdef CSR_HDMI_OUT1_BASE 565 | #error "not here!" 566 | /* hdmi_out1 */ 567 | #ifdef CSR_HDMI_IN0_BASE 568 | if(processor_hdmi_out1_source == VIDEO_IN_HDMI_IN0) 569 | hdmi_out1_core_initiator_base_write(hdmi_in0_framebuffer_base(hdmi_in0_fb_index)); 570 | #endif 571 | #ifdef CSR_HDMI_IN1_BASE 572 | if(processor_hdmi_out1_source == VIDEO_IN_HDMI_IN1) 573 | hdmi_out1_core_initiator_base_write(hdmi_in1_framebuffer_base(hdmi_in1_fb_index)); 574 | #endif 575 | if(processor_hdmi_out1_source == VIDEO_IN_PATTERN) 576 | hdmi_out1_core_initiator_base_write(pattern_framebuffer_base()); 577 | #endif 578 | 579 | 580 | #ifdef ENCODER_BASE 581 | #error "not here!" 582 | /* encoder */ 583 | #ifdef CSR_HDMI_IN0_BASE 584 | if(processor_encoder_source == VIDEO_IN_HDMI_IN0) { 585 | encoder_reader_base_write(hdmi_in0_framebuffer_base(hdmi_in0_fb_index)); 586 | } 587 | #endif 588 | #ifdef CSR_HDMI_IN1_BASE 589 | if(processor_encoder_source == VIDEO_IN_HDMI_IN1) { 590 | encoder_reader_base_write(hdmi_in1_framebuffer_base(hdmi_in1_fb_index)); 591 | } 592 | #endif 593 | if(processor_encoder_source == VIDEO_IN_PATTERN) 594 | encoder_reader_base_write(pattern_framebuffer_base()); 595 | #endif 596 | } 597 | 598 | void processor_service(void) 599 | { 600 | const struct video_timing *m = &video_modes[processor_mode]; 601 | #ifdef CSR_HDMI_IN0_BASE 602 | hdmi_in0_service(m->pixel_clock); // HDMI in 0 is a passthrough 603 | #endif 604 | #ifdef CSR_HDMI_IN1_BASE 605 | hdmi_in1_service(m->pixel_clock); 606 | #endif 607 | processor_update(); 608 | #ifdef ENCODER_BASE 609 | encoder_service(); 610 | #endif 611 | 612 | } 613 | -------------------------------------------------------------------------------- /software/pcie/kernel/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * LitePCIe driver 3 | * 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "litepcie.h" 27 | #include "config.h" 28 | #include "csr.h" 29 | #include "flags.h" 30 | 31 | #define LITEPCIE_NAME "litepcie" 32 | #define LITEPCIE_MINOR_COUNT 4 33 | 34 | #define DMA_BUFFER_SIZE PAGE_ALIGN(32768) 35 | #define DMA_BUFFER_MAP_SIZE (DMA_BUFFER_SIZE * DMA_BUFFER_COUNT) 36 | 37 | #define IRQ_MASK_DMA_READER (1 << DMA_READER_INTERRUPT) 38 | #define IRQ_MASK_DMA_WRITER (1 << DMA_WRITER_INTERRUPT) 39 | 40 | typedef struct { 41 | int minor; 42 | struct pci_dev *dev; 43 | 44 | phys_addr_t bar0_phys_addr; 45 | uint8_t *bar0_addr; /* virtual address of BAR0 */ 46 | 47 | uint8_t *dma_tx_bufs[DMA_BUFFER_COUNT]; 48 | unsigned long dma_tx_bufs_addr[DMA_BUFFER_COUNT]; 49 | uint8_t *dma_rx_bufs[DMA_BUFFER_COUNT]; 50 | unsigned long dma_rx_bufs_addr[DMA_BUFFER_COUNT]; 51 | uint8_t tx_dma_started; 52 | uint8_t rx_dma_started; 53 | wait_queue_head_t dma_waitqueue; 54 | } LitePCIeState; 55 | 56 | static dev_t litepcie_cdev; 57 | static struct cdev litepcie_cdev_struct; 58 | static LitePCIeState *litepcie_minor_table[LITEPCIE_MINOR_COUNT]; 59 | 60 | static void litepcie_end(struct pci_dev *dev, LitePCIeState *s); 61 | static int litepcie_dma_stop(LitePCIeState *s); 62 | 63 | static inline uint32_t litepcie_readl(LitePCIeState *s, uint32_t addr) 64 | { 65 | return readl(s->bar0_addr + addr); 66 | } 67 | 68 | static inline void litepcie_writel(LitePCIeState *s, uint32_t addr, uint32_t val) 69 | { 70 | return writel(val, s->bar0_addr + addr); 71 | } 72 | 73 | static void litepcie_enable_interrupt(LitePCIeState *s, int irq_num) 74 | { 75 | uint32_t v; 76 | v = litepcie_readl(s, CSR_MSI_ENABLE_ADDR); 77 | v |= (1 << irq_num); 78 | litepcie_writel(s, CSR_MSI_ENABLE_ADDR, v); 79 | } 80 | 81 | static void litepcie_disable_interrupt(LitePCIeState *s, int irq_num) 82 | { 83 | uint32_t v; 84 | v = litepcie_readl(s, CSR_MSI_ENABLE_ADDR); 85 | v &= ~(1 << irq_num); 86 | litepcie_writel(s, CSR_MSI_ENABLE_ADDR, v); 87 | } 88 | 89 | static int litepcie_open(struct inode *inode, struct file *file) 90 | { 91 | LitePCIeState *s; 92 | int minor; 93 | 94 | /* find PCI device */ 95 | minor = iminor(inode); 96 | if (minor < 0 || minor >= LITEPCIE_MINOR_COUNT) 97 | return -ENODEV; 98 | s = litepcie_minor_table[minor]; 99 | if (!s) 100 | return -ENODEV; 101 | file->private_data = s; 102 | return 0; 103 | } 104 | 105 | /* mmap the DMA buffers and registers to user space */ 106 | static int litepcie_mmap(struct file *file, struct vm_area_struct *vma) 107 | { 108 | LitePCIeState *s = file->private_data; 109 | unsigned long pfn; 110 | int is_tx, i; 111 | 112 | if (vma->vm_pgoff == 0) { 113 | if (vma->vm_end - vma->vm_start != DMA_BUFFER_MAP_SIZE) 114 | return -EINVAL; 115 | is_tx = 1; 116 | goto remap_ram; 117 | } else if (vma->vm_pgoff == (DMA_BUFFER_MAP_SIZE >> PAGE_SHIFT)) { 118 | if (vma->vm_end - vma->vm_start != DMA_BUFFER_MAP_SIZE) 119 | return -EINVAL; 120 | is_tx = 0; 121 | remap_ram: 122 | for(i = 0; i < DMA_BUFFER_COUNT; i++) { 123 | if (is_tx) 124 | pfn = __pa(s->dma_tx_bufs[i]) >> PAGE_SHIFT; 125 | else 126 | pfn = __pa(s->dma_rx_bufs[i]) >> PAGE_SHIFT; 127 | /* Note: the memory is cached, so the user must explicitly 128 | flush the CPU caches on architectures which require it. */ 129 | if (remap_pfn_range(vma, vma->vm_start + i * DMA_BUFFER_SIZE, pfn, 130 | DMA_BUFFER_SIZE, vma->vm_page_prot)) { 131 | printk(KERN_ERR LITEPCIE_NAME " remap_pfn_range failed\n"); 132 | return -EAGAIN; 133 | } 134 | } 135 | } else if (vma->vm_pgoff == ((2 * DMA_BUFFER_MAP_SIZE) >> PAGE_SHIFT)) { 136 | if (vma->vm_end - vma->vm_start != PCI_FPGA_BAR0_SIZE) 137 | return -EINVAL; 138 | pfn = s->bar0_phys_addr >> PAGE_SHIFT; 139 | /* not cached */ 140 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 141 | vma->vm_flags |= VM_IO; 142 | if (io_remap_pfn_range(vma, vma->vm_start, pfn, 143 | vma->vm_end - vma->vm_start, 144 | vma->vm_page_prot)) { 145 | printk(KERN_ERR LITEPCIE_NAME " io_remap_pfn_range failed\n"); 146 | return -EAGAIN; 147 | } 148 | } else { 149 | return -EINVAL; 150 | } 151 | 152 | return 0; 153 | } 154 | 155 | static int litepcie_release(struct inode *inode, struct file *file) 156 | { 157 | LitePCIeState *s = file->private_data; 158 | 159 | litepcie_dma_stop(s); /* just in case: stop the DMA */ 160 | return 0; 161 | } 162 | 163 | static irqreturn_t litepcie_interrupt(int irq, void *data) 164 | { 165 | LitePCIeState *s = data; 166 | uint32_t clear_mask, irq_vector; 167 | 168 | irq_vector = litepcie_readl(s, CSR_MSI_VECTOR_ADDR); 169 | clear_mask = 0; 170 | if (irq_vector & (IRQ_MASK_DMA_READER | IRQ_MASK_DMA_WRITER)) { 171 | /* wake up processes waiting on dma_wait() */ 172 | wake_up_interruptible(&s->dma_waitqueue); 173 | clear_mask |= (IRQ_MASK_DMA_READER | IRQ_MASK_DMA_WRITER); 174 | } 175 | 176 | litepcie_writel(s, CSR_MSI_CLEAR_ADDR, clear_mask); 177 | 178 | return IRQ_HANDLED; 179 | } 180 | 181 | static int litepcie_dma_start(LitePCIeState *s, struct litepcie_ioctl_dma_start *m) 182 | { 183 | int i, val; 184 | 185 | if (s->tx_dma_started || s->rx_dma_started) 186 | return -EIO; 187 | 188 | if (m->tx_buf_size == 0 && m->rx_buf_size == 0) 189 | return -EINVAL; 190 | /* check alignment (XXX: what is the exact constraint ?) */ 191 | if ((m->tx_buf_size & 7) != 0 || 192 | (m->rx_buf_size & 7) != 0 || 193 | m->tx_buf_size > DMA_BUFFER_SIZE || 194 | m->rx_buf_size > DMA_BUFFER_SIZE) 195 | return -EINVAL; 196 | 197 | /* check buffer count */ 198 | if (m->tx_buf_count > DMA_BUFFER_COUNT) 199 | return -EINVAL; 200 | if (m->rx_buf_count > DMA_BUFFER_COUNT) 201 | return -EINVAL; 202 | 203 | val = ((m->dma_flags & DMA_LOOPBACK_ENABLE) != 0); 204 | litepcie_writel(s, CSR_DMA_LOOPBACK_ENABLE_ADDR, val); 205 | 206 | /* init DMA write */ 207 | if (m->rx_buf_size != 0) { 208 | litepcie_writel(s, CSR_DMA_WRITER_ENABLE_ADDR, 0); 209 | litepcie_writel(s, CSR_DMA_WRITER_TABLE_FLUSH_ADDR, 1); 210 | litepcie_writel(s, CSR_DMA_WRITER_TABLE_LOOP_PROG_N_ADDR, 0); 211 | for(i = 0; i < m->rx_buf_count; i++) { 212 | litepcie_writel(s, CSR_DMA_WRITER_TABLE_VALUE_ADDR, m->rx_buf_size); 213 | litepcie_writel(s, CSR_DMA_WRITER_TABLE_VALUE_ADDR + 4, 214 | s->dma_rx_bufs_addr[i]); 215 | litepcie_writel(s, CSR_DMA_WRITER_TABLE_WE_ADDR, 1); 216 | } 217 | litepcie_writel(s, CSR_DMA_WRITER_TABLE_LOOP_PROG_N_ADDR, 1); 218 | } 219 | 220 | /* init DMA read */ 221 | if (m->tx_buf_size != 0) { 222 | litepcie_writel(s, CSR_DMA_READER_ENABLE_ADDR, 0); 223 | litepcie_writel(s, CSR_DMA_READER_TABLE_FLUSH_ADDR, 1); 224 | litepcie_writel(s, CSR_DMA_READER_TABLE_LOOP_PROG_N_ADDR, 0); 225 | for(i = 0; i < m->tx_buf_count; i++) { 226 | litepcie_writel(s, CSR_DMA_READER_TABLE_VALUE_ADDR, m->tx_buf_size); 227 | litepcie_writel(s, CSR_DMA_READER_TABLE_VALUE_ADDR + 4, 228 | s->dma_tx_bufs_addr[i]); 229 | litepcie_writel(s, CSR_DMA_READER_TABLE_WE_ADDR, 1); 230 | } 231 | litepcie_writel(s, CSR_DMA_READER_TABLE_LOOP_PROG_N_ADDR, 1); 232 | } 233 | 234 | /* start DMA */ 235 | if (m->rx_buf_size != 0) { 236 | litepcie_writel(s, CSR_DMA_WRITER_ENABLE_ADDR, 1); 237 | s->rx_dma_started = 1; 238 | } 239 | if (m->tx_buf_size != 0) { 240 | litepcie_writel(s, CSR_DMA_READER_ENABLE_ADDR, 1); 241 | s->tx_dma_started = 1; 242 | } 243 | 244 | return 0; 245 | } 246 | 247 | static int litepcie_dma_wait(LitePCIeState *s, struct litepcie_ioctl_dma_wait *m) 248 | { 249 | unsigned long timeout; 250 | int ret, last_buf_num; 251 | DECLARE_WAITQUEUE(wait, current); 252 | 253 | if (m->tx_wait) { 254 | if (!s->tx_dma_started) 255 | return -EIO; 256 | last_buf_num = m->tx_buf_num; 257 | litepcie_enable_interrupt(s, DMA_READER_INTERRUPT); 258 | } else { 259 | if (!s->rx_dma_started) 260 | return -EIO; 261 | last_buf_num = m->rx_buf_num; 262 | litepcie_enable_interrupt(s, DMA_WRITER_INTERRUPT); 263 | } 264 | 265 | add_wait_queue(&s->dma_waitqueue, &wait); 266 | 267 | timeout = jiffies + msecs_to_jiffies(m->timeout); 268 | for (;;) { 269 | /* set current buffer */ 270 | if (s->tx_dma_started) { 271 | m->tx_buf_num = (litepcie_readl(s, CSR_DMA_READER_TABLE_LOOP_STATUS_ADDR) & 0xffff); 272 | } else { 273 | m->tx_buf_num = 0; 274 | } 275 | if (s->rx_dma_started) { 276 | m->rx_buf_num = (litepcie_readl(s, CSR_DMA_WRITER_TABLE_LOOP_STATUS_ADDR) & 0xffff); 277 | } else { 278 | m->rx_buf_num = 0; 279 | } 280 | if (m->tx_wait) { 281 | if (m->tx_buf_num != last_buf_num) 282 | break; 283 | } else { 284 | if (m->rx_buf_num != last_buf_num) 285 | break; 286 | } 287 | if ((long)(jiffies - timeout) > 0) { 288 | ret = -EAGAIN; 289 | goto done; 290 | } 291 | set_current_state(TASK_INTERRUPTIBLE); 292 | if (signal_pending(current)) { 293 | ret = -EINTR; 294 | goto done; 295 | } 296 | schedule(); 297 | } 298 | ret = 0; 299 | done: 300 | if (m->tx_wait) { 301 | litepcie_disable_interrupt(s, DMA_READER_INTERRUPT); 302 | } else { 303 | litepcie_disable_interrupt(s, DMA_WRITER_INTERRUPT); 304 | } 305 | 306 | __set_current_state(TASK_RUNNING); 307 | remove_wait_queue(&s->dma_waitqueue, &wait); 308 | return ret; 309 | } 310 | 311 | static int litepcie_dma_stop(LitePCIeState *s) 312 | { 313 | /* just to be sure, we disable the interrupts */ 314 | litepcie_disable_interrupt(s, DMA_READER_INTERRUPT); 315 | litepcie_disable_interrupt(s, DMA_WRITER_INTERRUPT); 316 | 317 | s->tx_dma_started = 0; 318 | litepcie_writel(s, CSR_DMA_READER_TABLE_LOOP_PROG_N_ADDR, 0); 319 | litepcie_writel(s, CSR_DMA_READER_TABLE_FLUSH_ADDR, 1); 320 | udelay(100); 321 | litepcie_writel(s, CSR_DMA_READER_ENABLE_ADDR, 0); 322 | 323 | s->rx_dma_started = 0; 324 | litepcie_writel(s, CSR_DMA_WRITER_TABLE_LOOP_PROG_N_ADDR, 0); 325 | litepcie_writel(s, CSR_DMA_WRITER_TABLE_FLUSH_ADDR, 1); 326 | udelay(100); 327 | litepcie_writel(s, CSR_DMA_WRITER_ENABLE_ADDR, 0); 328 | 329 | return 0; 330 | } 331 | 332 | static long litepcie_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 333 | { 334 | LitePCIeState *s = file->private_data; 335 | long ret; 336 | 337 | switch(cmd) { 338 | case LITEPCIE_IOCTL_GET_MMAP_INFO: 339 | { 340 | struct litepcie_ioctl_mmap_info m; 341 | m.dma_tx_buf_offset = 0; 342 | m.dma_tx_buf_size = DMA_BUFFER_SIZE; 343 | m.dma_tx_buf_count = DMA_BUFFER_COUNT; 344 | 345 | m.dma_rx_buf_offset = DMA_BUFFER_MAP_SIZE; 346 | m.dma_rx_buf_size = DMA_BUFFER_SIZE; 347 | m.dma_rx_buf_count = DMA_BUFFER_COUNT; 348 | 349 | m.reg_offset = 2 * DMA_BUFFER_MAP_SIZE; 350 | m.reg_size = PCI_FPGA_BAR0_SIZE; 351 | if (copy_to_user((void *)arg, &m, sizeof(m))) { 352 | ret = -EFAULT; 353 | break; 354 | } 355 | ret = 0; 356 | } 357 | break; 358 | case LITEPCIE_IOCTL_DMA_START: 359 | { 360 | struct litepcie_ioctl_dma_start m; 361 | 362 | if (copy_from_user(&m, (void *)arg, sizeof(m))) { 363 | ret = -EFAULT; 364 | break; 365 | } 366 | ret = litepcie_dma_start(s, &m); 367 | } 368 | break; 369 | case LITEPCIE_IOCTL_DMA_STOP: 370 | { 371 | ret = litepcie_dma_stop(s); 372 | } 373 | break; 374 | case LITEPCIE_IOCTL_DMA_WAIT: 375 | { 376 | struct litepcie_ioctl_dma_wait m; 377 | 378 | if (copy_from_user(&m, (void *)arg, sizeof(m))) { 379 | ret = -EFAULT; 380 | break; 381 | } 382 | ret = litepcie_dma_wait(s, &m); 383 | if (ret == 0) { 384 | if (copy_to_user((void *)arg, &m, sizeof(m))) { 385 | ret = -EFAULT; 386 | break; 387 | } 388 | } 389 | } 390 | break; 391 | default: 392 | ret = -ENOIOCTLCMD; 393 | break; 394 | } 395 | return ret; 396 | } 397 | 398 | static const struct file_operations litepcie_fops = { 399 | .owner = THIS_MODULE, 400 | .unlocked_ioctl = litepcie_ioctl, 401 | .open = litepcie_open, 402 | .release = litepcie_release, 403 | .mmap = litepcie_mmap, 404 | .llseek = no_llseek, 405 | }; 406 | 407 | static int litepcie_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) 408 | { 409 | LitePCIeState *s = NULL; 410 | uint8_t rev_id; 411 | int ret, minor, i; 412 | 413 | printk(KERN_INFO LITEPCIE_NAME " Probing device\n"); 414 | 415 | /* find available minor */ 416 | for(minor = 0; minor < LITEPCIE_MINOR_COUNT; minor++) { 417 | if (!litepcie_minor_table[minor]) 418 | break; 419 | } 420 | if (minor == LITEPCIE_MINOR_COUNT) { 421 | printk(KERN_ERR LITEPCIE_NAME " Cannot allocate a minor\n"); 422 | ret = -ENODEV; 423 | goto fail1; 424 | } 425 | 426 | s = kzalloc(sizeof(LitePCIeState), GFP_KERNEL); 427 | if (!s) { 428 | printk(KERN_ERR LITEPCIE_NAME " Cannot allocate memory\n"); 429 | ret = -ENOMEM; 430 | goto fail1; 431 | } 432 | s->minor = minor; 433 | s->dev = dev; 434 | pci_set_drvdata(dev, s); 435 | 436 | ret = pci_enable_device(dev); 437 | if (ret != 0) { 438 | printk(KERN_ERR LITEPCIE_NAME " Cannot enable device\n"); 439 | goto fail1; 440 | } 441 | 442 | /* check device version */ 443 | pci_read_config_byte(dev, PCI_REVISION_ID, &rev_id); 444 | if (rev_id != 1) { 445 | printk(KERN_ERR LITEPCIE_NAME " Unsupported device version %d\n", rev_id); 446 | goto fail2; 447 | } 448 | 449 | if (pci_request_regions(dev, LITEPCIE_NAME) < 0) { 450 | printk(KERN_ERR LITEPCIE_NAME " Could not request regions\n"); 451 | goto fail2; 452 | } 453 | 454 | /* check BAR0 config */ 455 | if (!(pci_resource_flags(dev, 0) & IORESOURCE_MEM)) { 456 | printk(KERN_ERR LITEPCIE_NAME " Invalid BAR0 config\n"); 457 | goto fail3; 458 | } 459 | 460 | s->bar0_phys_addr = pci_resource_start(dev, 0); 461 | s->bar0_addr = pci_ioremap_bar(dev, 0); 462 | if (!s->bar0_addr) { 463 | printk(KERN_ERR LITEPCIE_NAME " Could not map BAR0\n"); 464 | goto fail3; 465 | } 466 | 467 | pci_set_master(dev); 468 | ret = pci_set_dma_mask(dev, DMA_BIT_MASK(32)); 469 | if (ret) { 470 | printk(KERN_ERR LITEPCIE_NAME " Failed to set DMA mask\n"); 471 | goto fail4; 472 | }; 473 | 474 | ret = pci_enable_msi(dev); 475 | if (ret) { 476 | printk(KERN_ERR LITEPCIE_NAME " Failed to enable MSI\n"); 477 | goto fail4; 478 | } 479 | 480 | if (request_irq(dev->irq, litepcie_interrupt, IRQF_SHARED, LITEPCIE_NAME, s) < 0) { 481 | printk(KERN_ERR LITEPCIE_NAME " Failed to allocate irq %d\n", dev->irq); 482 | goto fail5; 483 | } 484 | 485 | /* allocate DMA buffers */ 486 | for(i = 0; i < DMA_BUFFER_COUNT; i++) { 487 | s->dma_tx_bufs[i] = kzalloc(DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA32); 488 | if (!s->dma_tx_bufs[i]) { 489 | printk(KERN_ERR LITEPCIE_NAME " Failed to allocate dma_tx_buf\n"); 490 | goto fail6; 491 | } 492 | s->dma_tx_bufs_addr[i] = pci_map_single(dev, s->dma_tx_bufs[i], 493 | DMA_BUFFER_SIZE, 494 | DMA_TO_DEVICE); 495 | if (!s->dma_tx_bufs_addr[i]) { 496 | ret = -ENOMEM; 497 | goto fail6; 498 | } 499 | } 500 | 501 | for(i = 0; i < DMA_BUFFER_COUNT; i++) { 502 | s->dma_rx_bufs[i] = kzalloc(DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA32); 503 | if (!s->dma_rx_bufs[i]) { 504 | printk(KERN_ERR LITEPCIE_NAME " Failed to allocate dma_rx_buf\n"); 505 | goto fail6; 506 | } 507 | 508 | s->dma_rx_bufs_addr[i] = pci_map_single(dev, s->dma_rx_bufs[i], 509 | DMA_BUFFER_SIZE, 510 | DMA_FROM_DEVICE); 511 | if (!s->dma_rx_bufs_addr[i]) { 512 | ret = -ENOMEM; 513 | goto fail6; 514 | } 515 | } 516 | 517 | init_waitqueue_head(&s->dma_waitqueue); 518 | 519 | litepcie_minor_table[minor] = s; 520 | printk(KERN_INFO LITEPCIE_NAME " Assigned to minor %d\n", minor); 521 | return 0; 522 | 523 | fail6: 524 | litepcie_end(dev, s); 525 | free_irq(dev->irq, s); 526 | fail5: 527 | pci_disable_msi(dev); 528 | fail4: 529 | pci_iounmap(dev, s->bar0_addr); 530 | fail3: 531 | pci_release_regions(dev); 532 | fail2: 533 | pci_disable_device(dev); 534 | ret = -EIO; 535 | fail1: 536 | kfree(s); 537 | printk(KERN_ERR LITEPCIE_NAME " Error while probing device\n"); 538 | return ret; 539 | } 540 | 541 | static void litepcie_end(struct pci_dev *dev, LitePCIeState *s) 542 | { 543 | int i; 544 | 545 | for(i = 0; i < DMA_BUFFER_COUNT; i++) { 546 | if (s->dma_tx_bufs_addr[i]) { 547 | dma_unmap_single(&dev->dev, s->dma_tx_bufs_addr[i], 548 | DMA_BUFFER_SIZE, DMA_TO_DEVICE); 549 | } 550 | kfree(s->dma_tx_bufs[i]); 551 | } 552 | 553 | for(i = 0; i < DMA_BUFFER_COUNT; i++) { 554 | if (s->dma_rx_bufs_addr[i]) { 555 | dma_unmap_single(&dev->dev, s->dma_rx_bufs_addr[i], 556 | DMA_BUFFER_SIZE, DMA_FROM_DEVICE); 557 | } 558 | kfree(s->dma_rx_bufs[i]); 559 | } 560 | } 561 | 562 | static void litepcie_pci_remove(struct pci_dev *dev) 563 | { 564 | LitePCIeState *s = pci_get_drvdata(dev); 565 | 566 | printk(KERN_INFO LITEPCIE_NAME " Removing device\n"); 567 | litepcie_minor_table[s->minor] = NULL; 568 | 569 | litepcie_end(dev, s); 570 | free_irq(dev->irq, s); 571 | pci_disable_msi(dev); 572 | pci_iounmap(dev, s->bar0_addr); 573 | pci_disable_device(dev); 574 | pci_release_regions(dev); 575 | kfree(s); 576 | }; 577 | 578 | static const struct pci_device_id litepcie_pci_ids[] = { 579 | { PCI_DEVICE(PCI_FPGA_VENDOR_ID, PCI_FPGA_DEVICE_ID), }, 580 | { 0, } 581 | }; 582 | MODULE_DEVICE_TABLE(pci, litepcie_pci_ids); 583 | 584 | 585 | static struct pci_driver litepcie_pci_driver = { 586 | .name = LITEPCIE_NAME, 587 | .id_table = litepcie_pci_ids, 588 | .probe = litepcie_pci_probe, 589 | .remove = litepcie_pci_remove, 590 | }; 591 | 592 | static int __init litepcie_module_init(void) 593 | { 594 | int ret; 595 | 596 | ret = pci_register_driver(&litepcie_pci_driver); 597 | if (ret < 0) { 598 | printk(KERN_ERR LITEPCIE_NAME " Error while registering PCI driver\n"); 599 | goto fail1; 600 | } 601 | 602 | ret = alloc_chrdev_region(&litepcie_cdev, 0, LITEPCIE_MINOR_COUNT, LITEPCIE_NAME); 603 | if (ret < 0) { 604 | printk(KERN_ERR LITEPCIE_NAME " Could not allocate char device\n"); 605 | goto fail2; 606 | } 607 | 608 | cdev_init(&litepcie_cdev_struct, &litepcie_fops); 609 | ret = cdev_add(&litepcie_cdev_struct, litepcie_cdev, LITEPCIE_MINOR_COUNT); 610 | if (ret < 0) { 611 | printk(KERN_ERR LITEPCIE_NAME " Could not register char device\n"); 612 | goto fail3; 613 | } 614 | return 0; 615 | fail3: 616 | unregister_chrdev_region(litepcie_cdev, LITEPCIE_MINOR_COUNT); 617 | fail2: 618 | pci_unregister_driver(&litepcie_pci_driver); 619 | fail1: 620 | return ret; 621 | } 622 | 623 | static void __exit litepcie_module_exit(void) 624 | { 625 | cdev_del(&litepcie_cdev_struct); 626 | unregister_chrdev_region(litepcie_cdev, LITEPCIE_MINOR_COUNT); 627 | 628 | pci_unregister_driver(&litepcie_pci_driver); 629 | } 630 | 631 | 632 | module_init(litepcie_module_init); 633 | module_exit(litepcie_module_exit); 634 | 635 | MODULE_LICENSE("GPL"); 636 | -------------------------------------------------------------------------------- /firmware/ci.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "stdio_wrap.h" 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "flags.h" 13 | 14 | #include "asm.h" 15 | #include "config.h" 16 | #include "hdmi_in0.h" 17 | #include "hdmi_in1.h" 18 | #include "processor.h" 19 | #include "mmcm.h" 20 | #include "ci.h" 21 | #include "encoder.h" 22 | #include "hdmi_out0.h" 23 | #include "bist.h" 24 | #include "dump.h" 25 | #include "edid.h" 26 | 27 | int status_enabled; 28 | extern const struct video_timing video_modes[]; 29 | 30 | static void help_video_matrix(void) 31 | { 32 | wputs("video_matrix list - list available video sinks and sources"); 33 | wputs("video_matrix connect - connect video source to video sink"); 34 | wputs(" "); 35 | } 36 | 37 | static void help_video_mode(void) 38 | { 39 | wputs("video_mode list - list available video modes"); 40 | wputs("video_mode - select video mode"); 41 | } 42 | 43 | static void help_hdp_toggle(void) 44 | { 45 | wputs("hdp_toggle - toggle HDP on source for EDID rescan"); 46 | } 47 | 48 | static void help_status(void) 49 | { 50 | wputs("status - print status message once"); 51 | wputs("status - repeatedly print status message"); 52 | } 53 | 54 | #ifdef CSR_HDMI_OUT0_BASE 55 | static void help_output0(void) 56 | { 57 | wputs("output0 on - enable output0"); 58 | wputs("output0 off - disable output0"); 59 | } 60 | #endif 61 | 62 | #ifdef CSR_HDMI_OUT1_BASE 63 | static void help_output1(void) 64 | { 65 | wputs("output1 on - enable output1"); 66 | wputs("output1 off - disable output1"); 67 | } 68 | #endif 69 | 70 | #ifdef ENCODER_BASE 71 | static void help_encoder(void) 72 | { 73 | wputs("encoder on - enable encoder"); 74 | wputs("encoder off - disable encoder"); 75 | wputs("encoder quality - select quality"); 76 | wputs("encoder fps - configure target fps"); 77 | } 78 | #endif 79 | 80 | #ifdef CSR_DMA_WRITER_BASE 81 | static void help_dma_writer(void) 82 | { 83 | wputs("dma_writer on - enable dma_writer"); 84 | wputs("dma_writer off - disable dma_writer"); 85 | } 86 | #endif 87 | 88 | #ifdef CSR_DMA_READER_BASE 89 | static void help_dma_reader(void) 90 | { 91 | wputs("dma_reader on - enable dma_reader"); 92 | wputs("dma reader off - disable dma_reader"); 93 | } 94 | #endif 95 | 96 | #ifdef CSR_GENERATOR_BASE 97 | static void help_sdram_test(void) 98 | { 99 | wputs("sdram_test - Run SDRAM BIST checker"); 100 | 101 | } 102 | #endif 103 | 104 | static void help_debug(void) 105 | { 106 | wputs("debug mmcm - dump mmcm configuration"); 107 | #ifdef CSR_SDRAM_CONTROLLER_BANDWIDTH_UPDATE_ADDR 108 | wputs("debug ddr - show DDR bandwidth"); 109 | #endif 110 | wputs("debug dna - show Board's DNA"); 111 | wputs("debug edid - dump monitor EDID"); 112 | } 113 | 114 | static void ci_help(void) 115 | { 116 | wputs("help - this command"); 117 | wputs("reboot - reboot CPU"); 118 | wputs(""); 119 | wputs("mr - read address space"); 120 | wputs("mw - write address space"); 121 | wputs("mc - copy address space"); 122 | wputs(""); 123 | help_status(); 124 | wputs(""); 125 | help_video_matrix(); 126 | wputs(""); 127 | help_video_mode(); 128 | wputs(""); 129 | help_hdp_toggle(); 130 | wputs(""); 131 | #ifdef CSR_HDMI_OUT0_BASE 132 | help_output0(); 133 | wputs(""); 134 | #endif 135 | #ifdef CSR_HDMI_OUT1_BASE 136 | help_output1(); 137 | wputs(""); 138 | #endif 139 | #ifdef ENCODER_BASE 140 | help_encoder(); 141 | wputs(""); 142 | #endif 143 | #ifdef CSR_DMA_WRITER_BASE 144 | help_dma_writer(); 145 | wputs(""); 146 | #endif 147 | #ifdef CSR_DMA_READER_BASE 148 | help_dma_reader(); 149 | wputs(""); 150 | #endif 151 | #ifdef CSR_GENERATOR_BASE 152 | help_sdram_test(); 153 | wputs(""); 154 | #endif 155 | wputs(""); 156 | help_debug(); 157 | } 158 | 159 | static char *readstr(void) 160 | { 161 | char c[2]; 162 | static char s[64]; 163 | static int ptr = 0; 164 | 165 | if(readchar_nonblock()) { 166 | c[0] = readchar(); 167 | c[1] = 0; 168 | switch(c[0]) { 169 | case 0x7f: 170 | case 0x08: 171 | if(ptr > 0) { 172 | ptr--; 173 | wputsnonl("\x08 \x08"); 174 | } 175 | break; 176 | case 0x07: 177 | break; 178 | case '\r': 179 | case '\n': 180 | s[ptr] = 0x00; 181 | wputsnonl("\n"); 182 | ptr = 0; 183 | return s; 184 | default: 185 | if(ptr >= (sizeof(s) - 1)) 186 | break; 187 | wputsnonl(c); 188 | s[ptr] = c[0]; 189 | ptr++; 190 | break; 191 | } 192 | } 193 | 194 | return NULL; 195 | } 196 | 197 | static char *get_token_generic(char **str, char delimiter) 198 | { 199 | char *c, *d; 200 | 201 | c = (char *)strchr(*str, delimiter); 202 | if(c == NULL) { 203 | d = *str; 204 | *str = *str+strlen(*str); 205 | return d; 206 | } 207 | *c = 0; 208 | d = *str; 209 | *str = c+1; 210 | return d; 211 | } 212 | 213 | static char *get_token(char **str) 214 | { 215 | return get_token_generic(str, ' '); 216 | } 217 | 218 | static void reboot(void) 219 | { 220 | REBOOT; 221 | } 222 | 223 | static void status_enable(void) 224 | { 225 | wprintf("Enabling status\r\n"); 226 | status_enabled = 1; 227 | } 228 | 229 | static void status_disable(void) 230 | { 231 | wprintf("Disabling status\r\n"); 232 | status_enabled = 0; 233 | } 234 | 235 | static void debug_ddr(void); 236 | 237 | static void status_print(void) 238 | { 239 | 240 | #ifdef CSR_HDMI_IN0_BASE 241 | wprintf( 242 | "input0: %dx%d", 243 | hdmi_in0_resdetection_hres_read(), 244 | hdmi_in0_resdetection_vres_read()); 245 | #ifdef CSR_HDMI_IN0_FREQ_BASE 246 | wprintf(" (@ %3d.%2d MHz)", hdmi_in0_freq_value_read() / 1000000, 247 | (hdmi_in0_freq_value_read() / 10000) % 100); 248 | #endif 249 | wprintf("\r\n"); 250 | #endif 251 | 252 | #ifdef CSR_HDMI_IN1_BASE 253 | wprintf( 254 | "input1: %dx%d", 255 | hdmi_in1_resdetection_hres_read(), 256 | hdmi_in1_resdetection_vres_read()); 257 | #ifdef CSR_HDMI_IN1_FREQ_BASE 258 | wprintf(" (@ %3d.%2d MHz)", hdmi_in1_freq_value_read() / 1000000, 259 | (hdmi_in1_freq_value_read() / 10000) % 100); 260 | #endif 261 | wprintf("\r\n"); 262 | #endif 263 | 264 | #ifdef CSR_HDMI_OUT0_BASE 265 | unsigned int underflows; 266 | wprintf("output0: "); 267 | if(hdmi_out0_core_initiator_enable_read()) { 268 | hdmi_out0_core_underflow_enable_write(1); 269 | hdmi_out0_core_underflow_update_write(1); 270 | underflows = hdmi_out0_core_underflow_counter_read(); 271 | wprintf( 272 | "%dx%d@%dHz from %s (underflows: %d)", 273 | processor_h_active, 274 | processor_v_active, 275 | processor_refresh, 276 | processor_get_source_name(processor_hdmi_out0_source), 277 | underflows); 278 | hdmi_out0_core_underflow_enable_write(0); 279 | hdmi_out0_core_underflow_enable_write(1); 280 | } else 281 | wprintf("off"); 282 | wprintf("\r\n"); 283 | #endif 284 | 285 | #ifdef CSR_HDMI_OUT1_BASE 286 | wprintf("output1: "); 287 | if(hdmi_out1_core_initiator_enable_read()) { 288 | hdmi_out1_core_underflow_enable_write(1); 289 | hdmi_out1_core_underflow_update_write(1); 290 | underflows = hdmi_out1_core_underflow_counter_read(); 291 | wprintf( 292 | "%dx%d@%uHz from %s (underflows: %d)", 293 | processor_h_active, 294 | processor_v_active, 295 | processor_refresh, 296 | processor_get_source_name(processor_hdmi_out1_source), 297 | underflows); 298 | hdmi_out1_core_underflow_enable_write(0); 299 | hdmi_out1_core_underflow_enable_write(1); 300 | } else 301 | wprintf("off"); 302 | wprintf("\r\n"); 303 | #endif 304 | 305 | #ifdef ENCODER_BASE 306 | wprintf("encoder: "); 307 | if(encoder_enabled) { 308 | wprintf( 309 | "%dx%d @ %dfps from %s (q: %d)", 310 | processor_h_active, 311 | processor_v_active, 312 | encoder_fps, 313 | processor_get_source_name(processor_encoder_source), 314 | encoder_quality); 315 | } else 316 | wprintf("off"); 317 | wprintf("\r\n"); 318 | #endif 319 | #ifdef CSR_SDRAM_CONTROLLER_BANDWIDTH_UPDATE_ADDR 320 | wprintf("ddr: "); 321 | debug_ddr(); 322 | #endif 323 | #ifdef CSR_DMA_WRITER_BASE 324 | wprintf("DMA_WRITER overflows: %d\n", dma_writer_overflows_read()); 325 | #endif 326 | #ifdef CSR_DMA_READER_BASE 327 | wprintf("DMA_READER underflows: %d\n", dma_reader_underflows_read()); 328 | #endif 329 | } 330 | 331 | static void status_service(void) 332 | { 333 | static int last_event; 334 | 335 | if(elapsed(&last_event, SYSTEM_CLOCK_FREQUENCY)) { 336 | if(status_enabled) { 337 | status_print(); 338 | wprintf("\r\n"); 339 | } 340 | } 341 | } 342 | 343 | // FIXME 344 | #define HDMI_IN0_MNEMONIC "" 345 | #define HDMI_IN1_MNEMONIC "" 346 | #define HDMI_OUT0_MNEMONIC "" 347 | #define HDMI_OUT1_MNEMONIC "" 348 | 349 | #define HDMI_IN0_DESCRIPTION "" 350 | #define HDMI_IN1_DESCRIPTION "" 351 | #define HDMI_OUT0_DESCRIPTION "" 352 | #define HDMI_OUT1_DESCRIPTION "" 353 | // FIXME 354 | 355 | static void video_matrix_list(void) 356 | { 357 | wprintf("Video sources:\r\n"); 358 | #ifdef CSR_HDMI_IN0_BASE 359 | wprintf("input0: %s\r\n", HDMI_IN0_MNEMONIC); 360 | wputs(HDMI_IN0_DESCRIPTION); 361 | #endif 362 | #ifdef CSR_HDMI_IN1_BASE 363 | wprintf("input1: %s\r\n", HDMI_IN1_MNEMONIC); 364 | wputs(HDMI_IN1_DESCRIPTION); 365 | #endif 366 | wprintf("pattern:\r\n"); 367 | wprintf(" Video pattern\r\n"); 368 | wputs(" "); 369 | wprintf("Video sinks:\r\n"); 370 | #ifdef CSR_HDMI_OUT0_BASE 371 | wprintf("output0: %s\r\n", HDMI_OUT0_MNEMONIC); 372 | wputs(HDMI_OUT0_DESCRIPTION); 373 | #endif 374 | #ifdef CSR_HDMI_OUT1_BASE 375 | wprintf("output1: %s\r\n", HDMI_OUT1_MNEMONIC); 376 | wputs(HDMI_OUT1_DESCRIPTION); 377 | #endif 378 | #ifdef ENCODER_BASE 379 | wprintf("encoder:\r\n"); 380 | wprintf(" JPEG encoder (USB output)\r\n"); 381 | #endif 382 | wputs(" "); 383 | } 384 | 385 | static void video_matrix_connect(int source, int sink) 386 | { 387 | if(source >= 0 && source <= VIDEO_IN_PATTERN) 388 | { 389 | if(sink >= 0 && sink <= VIDEO_OUT_HDMI_OUT1) { 390 | wprintf("Connecting %s to output%d\r\n", processor_get_source_name(source), sink); 391 | if(sink == VIDEO_OUT_HDMI_OUT0) 392 | #ifdef CSR_HDMI_OUT0_BASE 393 | processor_set_hdmi_out0_source(source); 394 | #else 395 | wprintf("hdmi_out0 is missing.\r\n"); 396 | #endif 397 | else if(sink == VIDEO_OUT_HDMI_OUT1) 398 | #ifdef CSR_HDMI_OUT1_BASE 399 | processor_set_hdmi_out1_source(source); 400 | #else 401 | wprintf("hdmi_out1 is missing.\r\n"); 402 | #endif 403 | processor_update(); 404 | } 405 | #ifdef ENCODER_BASE 406 | else if(sink == VIDEO_OUT_ENCODER) { 407 | wprintf("Connecting %s to encoder\r\n", processor_get_source_name(source)); 408 | processor_set_encoder_source(source); 409 | processor_update(); 410 | } 411 | #endif 412 | } 413 | } 414 | 415 | static void video_mode_list(void) 416 | { 417 | char mode_descriptors[PROCESSOR_MODE_COUNT*PROCESSOR_MODE_DESCLEN]; 418 | int i; 419 | 420 | processor_list_modes(mode_descriptors); 421 | wprintf("Available video modes:\r\n"); 422 | for(i=0;i>=1) r++; 527 | return r; 528 | } 529 | 530 | #ifdef CSR_SDRAM_CONTROLLER_BANDWIDTH_UPDATE_ADDR 531 | static void debug_ddr(void) 532 | { 533 | unsigned long long int nr, nw; 534 | unsigned long long int f; 535 | unsigned int rdb, wrb; 536 | unsigned int burstbits; 537 | 538 | sdram_controller_bandwidth_update_write(1); 539 | nr = sdram_controller_bandwidth_nreads_read(); 540 | nw = sdram_controller_bandwidth_nwrites_read(); 541 | f = SYSTEM_CLOCK_FREQUENCY; 542 | burstbits = (2*DFII_NPHASES) << DFII_PIX_DATA_SIZE; 543 | rdb = (nr*f >> (27 - log2(burstbits)))/1000000ULL; 544 | wrb = (nw*f >> (27 - log2(burstbits)))/1000000ULL; 545 | wprintf("read:%5dMbps write:%5dMbps all:%5dMbps\r\n", rdb, wrb, rdb + wrb); 546 | } 547 | #endif 548 | 549 | #ifdef CSR_DNA_ID_ADDR 550 | static void print_board_dna(void) { 551 | int i; 552 | wprintf("Board's DNA: "); 553 | for(i=0; i"); 564 | } 565 | 566 | void ci_service(void) 567 | { 568 | char *str; 569 | char *token; 570 | char dummy[] = "dummy"; 571 | int was_dummy = 0; 572 | 573 | status_service(); 574 | 575 | str = readstr(); 576 | if(str == NULL) { 577 | str = (char *) dummy; 578 | } 579 | 580 | token = get_token(&str); 581 | 582 | if(strcmp(token, "help") == 0) { 583 | wputs("Available commands:"); 584 | token = get_token(&str); 585 | if(strcmp(token, "video_matrix") == 0) 586 | help_video_matrix(); 587 | else if(strcmp(token, "video_mode") == 0) 588 | help_video_mode(); 589 | else if(strcmp(token, "hdp_toggle") == 0) 590 | help_hdp_toggle(); 591 | #ifdef CSR_HDMI_OUT0_BASE 592 | else if(strcmp(token, "output0") == 0) 593 | help_output0(); 594 | #endif 595 | #ifdef CSR_HDMI_OUT1_BASE 596 | else if(strcmp(token, "output1") == 0) 597 | help_output1(); 598 | #endif 599 | #ifdef ENCODER_BASE 600 | else if(strcmp(token, "encoder") == 0) 601 | help_encoder(); 602 | #endif 603 | else if(strcmp(token, "debug") == 0) 604 | help_debug(); 605 | else 606 | ci_help(); 607 | wputs(""); 608 | } 609 | else if(strcmp(token, "reboot") == 0) reboot(); 610 | else if(strcmp(token, "mr") == 0) mr(get_token(&str), get_token(&str)); 611 | else if(strcmp(token, "mw") == 0) mw(get_token(&str), get_token(&str), get_token(&str)); 612 | else if(strcmp(token, "mc") == 0) mc(get_token(&str), get_token(&str), get_token(&str)); 613 | else if(strcmp(token, "video_matrix") == 0) { 614 | token = get_token(&str); 615 | if(strcmp(token, "list") == 0) { 616 | video_matrix_list(); 617 | } 618 | else if(strcmp(token, "connect") == 0) { 619 | int source; 620 | int sink; 621 | /* get video source */ 622 | token = get_token(&str); 623 | source = -1; 624 | if(strcmp(token, "input0") == 0) { 625 | source = VIDEO_IN_HDMI_IN0; 626 | } 627 | else if(strcmp(token, "input1") == 0) { 628 | source = VIDEO_IN_HDMI_IN1; 629 | } 630 | else if(strcmp(token, "pattern") == 0) { 631 | source = VIDEO_IN_PATTERN; 632 | } 633 | else { 634 | wprintf("Unknown video source: '%s'\r\n", token); 635 | } 636 | 637 | /* get video sink */ 638 | token = get_token(&str); 639 | sink = -1; 640 | if(strcmp(token, "output0") == 0) { 641 | sink = VIDEO_OUT_HDMI_OUT0; 642 | } 643 | else if(strcmp(token, "output1") == 0) { 644 | sink = VIDEO_OUT_HDMI_OUT1; 645 | } 646 | else if(strcmp(token, "encoder") == 0) { 647 | sink = VIDEO_OUT_ENCODER; 648 | } 649 | else 650 | wprintf("Unknown video sink: '%s'\r\n", token); 651 | 652 | if (source >= 0 && sink >= 0) 653 | video_matrix_connect(source, sink); 654 | else 655 | help_video_matrix(); 656 | } else { 657 | help_video_matrix(); 658 | } 659 | } 660 | else if(strcmp(token, "video_mode") == 0) { 661 | token = get_token(&str); 662 | if(strcmp(token, "list") == 0) 663 | video_mode_list(); 664 | else 665 | video_mode_set(atoi(token)); 666 | } 667 | else if(strcmp(token, "hdp_toggle") == 0) { 668 | token = get_token(&str); 669 | hdp_toggle(atoi(token)); 670 | } 671 | #ifdef CSR_HDMI_OUT0_BASE 672 | else if(strcmp(token, "output0") == 0) { 673 | token = get_token(&str); 674 | if(strcmp(token, "on") == 0) 675 | output0_on(); 676 | else if(strcmp(token, "off") == 0) 677 | output0_off(); 678 | else 679 | help_output0(); 680 | } 681 | #endif 682 | #ifdef CSR_HDMI_OUT1_BASE 683 | else if(strcmp(token, "output1") == 0) { 684 | token = get_token(&str); 685 | if(strcmp(token, "on") == 0) 686 | output1_on(); 687 | else if(strcmp(token, "off") == 0) 688 | output1_off(); 689 | else 690 | help_output1(); 691 | } 692 | #endif 693 | #ifdef ENCODER_BASE 694 | else if(strcmp(token, "encoder") == 0) { 695 | token = get_token(&str); 696 | if(strcmp(token, "on") == 0) 697 | encoder_on(); 698 | else if(strcmp(token, "off") == 0) 699 | encoder_off(); 700 | else if(strcmp(token, "quality") == 0) 701 | encoder_configure_quality(atoi(get_token(&str))); 702 | else if(strcmp(token, "fps") == 0) 703 | encoder_configure_fps(atoi(get_token(&str))); 704 | else 705 | help_encoder(); 706 | } 707 | #endif 708 | #ifdef CSR_GENERATOR_BASE 709 | else if(strcmp(token, "sdram_test") == 0) { 710 | bist_test(); 711 | } 712 | #endif 713 | #ifdef CSR_DMA_WRITER_BASE 714 | else if(strcmp(token, "dma_writer") == 0) { 715 | token = get_token(&str); 716 | if(strcmp(token, "on") == 0) { 717 | dma_writer_enable_write(1); 718 | dma_writer_start_write(1); 719 | wprintf("dma_writer on\n"); 720 | } else if(strcmp(token, "off") == 0) { 721 | dma_writer_enable_write(0); 722 | dma_writer_start_write(0); 723 | wprintf("dma_writer off\n"); 724 | } 725 | } 726 | #endif 727 | #ifdef CSR_DMA_READER_BASE 728 | else if(strcmp(token, "dma_reader") == 0) { 729 | token = get_token(&str); 730 | if(strcmp(token, "on") == 0) { 731 | dma_reader_enable_write(1); 732 | dma_reader_start_write(1); 733 | wprintf("dma_reader on\n"); 734 | } else if(strcmp(token, "off") == 0) { 735 | dma_reader_enable_write(0); 736 | dma_reader_start_write(0); 737 | wprintf("dma_reader off\n"); 738 | } 739 | } 740 | #endif 741 | 742 | else if(strcmp(token, "status") == 0) { 743 | token = get_token(&str); 744 | if(strcmp(token, "on") == 0) 745 | status_enable(); 746 | else if(strcmp(token, "off") == 0) 747 | status_disable(); 748 | else 749 | status_print(); 750 | } 751 | else if(strcmp(token, "debug") == 0) { 752 | token = get_token(&str); 753 | if(strcmp(token, "mmcm") == 0) 754 | debug_mmcm(); 755 | #ifdef CSR_HDMI_IN0_BASE 756 | else if(strcmp(token, "input0") == 0) { 757 | hdmi_in0_debug = !hdmi_in0_debug; 758 | wprintf("HDMI Input 0 debug %s\r\n", hdmi_in0_debug ? "on" : "off"); 759 | } 760 | #endif 761 | #ifdef CSR_HDMI_IN1_BASE 762 | else if(strcmp(token, "input1") == 0) { 763 | hdmi_in1_debug = !hdmi_in1_debug; 764 | wprintf("HDMI Input 1 debug %s\r\n", hdmi_in1_debug ? "on" : "off"); 765 | } 766 | #endif 767 | #ifdef CSR_SDRAM_CONTROLLER_BANDWIDTH_UPDATE_ADDR 768 | else if(strcmp(token, "ddr") == 0) 769 | debug_ddr(); 770 | #endif 771 | #ifdef CSR_DNA_ID_ADDR 772 | else if(strcmp(token, "dna") == 0) 773 | print_board_dna(); 774 | #endif 775 | else if(strcmp(token, "edid") == 0) { 776 | unsigned int found = 0; 777 | token = get_token(&str); 778 | #ifdef CSR_HDMI_OUT0_I2C_W_ADDR 779 | if(strcmp(token, "output0") == 0) { 780 | found = 1; 781 | hdmi_out0_print_edid(); 782 | } 783 | #endif 784 | #ifdef CSR_HDMI_OUT1_I2C_W_ADDR 785 | if(strcmp(token, "output1") == 0) { 786 | found = 1; 787 | hdmi_out1_print_edid(); 788 | } 789 | #endif 790 | if(found == 0) 791 | wprintf("%s port has no EDID capabilities\r\n", token); 792 | } else if(strcmp(token, "dma") == 0 ) { 793 | wprintf("initiating DMA on HDMI1\r\n"); 794 | hdmi_in1_dma_ev_enable_write(0x3); 795 | } else if(strcmp(token, "rect") == 0 ) { 796 | wprintf("enabling video_out0 writing\r\n"); 797 | hdmi_core_out0_initiator_enable_write(0); 798 | 799 | const struct video_timing *m = &video_modes[12]; 800 | m = &video_modes[12]; 801 | hdmi_core_out0_initiator_base_write(hdmi_in1_framebuffer_base(hdmi_in1_fb_index)); 802 | 803 | hdmi_core_out0_initiator_hres_write(m->h_active); 804 | hdmi_core_out0_initiator_hsync_start_write(m->h_active + m->h_sync_offset); 805 | hdmi_core_out0_initiator_hsync_end_write(m->h_active + m->h_sync_offset + m->h_sync_width); 806 | hdmi_core_out0_initiator_hscan_write(m->h_active + m->h_blanking - 1); 807 | hdmi_core_out0_initiator_vres_write(m->v_active); 808 | hdmi_core_out0_initiator_vsync_start_write(m->v_active + m->v_sync_offset); 809 | hdmi_core_out0_initiator_vsync_end_write(m->v_active + m->v_sync_offset + m->v_sync_width); 810 | hdmi_core_out0_initiator_vscan_write(m->v_active + m->v_blanking); 811 | 812 | hdmi_core_out0_initiator_length_write(m->h_active*m->v_active*4); 813 | 814 | rectangle_hrect_start_write(0); 815 | rectangle_hrect_end_write(1200); 816 | rectangle_vrect_start_write(0); 817 | rectangle_vrect_end_write(540); 818 | 819 | wprintf("out hres %d, hscan %d\r\n", hdmi_core_out0_initiator_hres_read(), hdmi_core_out0_initiator_hscan_read()); 820 | wprintf("out vres %d, vscan %d\r\n", hdmi_core_out0_initiator_vres_read(), hdmi_core_out0_initiator_vscan_read()); 821 | wprintf("out length %d\r\n", hdmi_core_out0_initiator_length_read()); 822 | 823 | hdmi_core_out0_dma_delay_base_write(80); // this helps align the DMA transfer through various delay offsets 824 | // empricially determined, will shift around depending on what you do in the overlay video pipe, e.g. 825 | // ycrcb422 vs rgb 826 | 827 | hdmi_core_out0_initiator_enable_write(1); 828 | } else if(strcmp(token, "setrect") == 0 ) { 829 | const struct video_timing *m = &video_modes[12]; 830 | m = &video_modes[12]; 831 | 832 | rectangle_hrect_start_write((unsigned short) strtoul(get_token(&str), NULL, 0)); 833 | rectangle_hrect_end_write((unsigned short) strtoul(get_token(&str), NULL, 0)); 834 | // vblank on top of frame so compensate in offset 835 | rectangle_vrect_start_write((unsigned short) strtoul(get_token(&str), NULL, 0) + m->v_blanking ); 836 | rectangle_vrect_end_write((unsigned short) strtoul(get_token(&str), NULL, 0) + m->v_blanking ); 837 | } else if(strcmp(token, "rectoff") == 0 ) { 838 | hdmi_core_out0_initiator_enable_write(0); 839 | } else if (strcmp(token, "delay") == 0) { 840 | hdmi_core_out0_dma_delay_base_write((unsigned int) strtoul(get_token(&str), NULL, 0)); 841 | wprintf("delay value: %d\r\n", hdmi_core_out0_dma_delay_base_read()); 842 | } else if (strcmp(token, "dvimode") == 0 ) { 843 | hdmi_in0_decode_terc4_dvimode_write(1); 844 | } else if (strcmp(token, "hdmimode") == 0 ) { 845 | hdmi_in0_decode_terc4_dvimode_write(0); 846 | } else 847 | help_debug(); 848 | } else if (strncmp(token, "dummy", 5) == 0) { 849 | was_dummy = 1; 850 | } else { 851 | // if(status_enabled) 852 | // status_disable(); 853 | } 854 | if( !was_dummy ) { 855 | ci_prompt(); 856 | } 857 | } 858 | --------------------------------------------------------------------------------