fix firmware smi high-z

bug_fixes_integration_tx
meexmachina 2021-08-10 14:27:21 +03:00
rodzic c0c28756fd
commit 6079cd4855
9 zmienionych plików z 16623 dodań i 16196 usunięć

Wyświetl plik

@ -50,14 +50,14 @@ module smi_ctrl
// ----------------
localparam
smi_address_idle = 3'b000,
smi_address_read_900 = 3'b001,
smi_address_read_2400 = 3'b010,
smi_address_read_res = 3'b011,
smi_address_write_900 = 3'b001,
smi_address_write_2400 = 3'b010,
smi_address_write_res2 = 3'b011,
smi_address_read_res1 = 3'b100,
smi_address_write_900 = 3'b101,
smi_address_write_2400 = 3'b110,
smi_address_write_res2 = 3'b111;
smi_address_read_900 = 3'b101,
smi_address_read_2400 = 3'b110,
smi_address_read_res = 3'b111;
always @(posedge i_sys_clk)
begin
if (i_reset) begin

Plik diff jest za duży Load Diff

Plik binarny nie jest wyświetlany.

Plik diff jest za duży Load Diff

Wyświetl plik

@ -41,7 +41,7 @@ module top(
input [3:0] i_config,
input i_button,
output o_ldo_2v8_en,
output [7:0] io_pmod,
inout [7:0] io_pmod,
output o_led0,
output o_led1,
@ -335,12 +335,12 @@ module top(
wire w_smi_writing;
assign w_smi_addr = {i_smi_a3, i_smi_a2, i_smi_a1};
assign io_smi_data = (w_smi_writing)?1'bZ:w_smi_data_output;
assign io_smi_data = (w_smi_writing)?w_smi_data_output:1'bZ;
assign w_smi_data_input = io_smi_data;
// Testing - output the clock signal (positive and negative) to the PMOD
assign io_pmod[0] = w_smi_read_req;
assign io_pmod[1] = w_smi_write_req;
assign io_pmod[0] = (w_smi_writing)?w_smi_read_req:1'bZ;
assign io_pmod[1] = (w_smi_writing)?w_smi_write_req:1'bZ;
assign io_pmod[2] = w_rx_09_fifo_empty;
assign io_pmod[3] = i_smi_soe_se;
assign io_pmod[7:4] = w_rx_09_fifo_data[5:2];

Wyświetl plik

@ -342,7 +342,7 @@ struct bcm2835_smi_instance *bcm2835_smi_get(struct device_node *node);
*/
#define SMIDSW_WWIDTH_MASK ((1<<31)|(1<<30))
#define SMIDSW_WWIDTH_OFFS (30)
#define SMIDSW_WSETUP_MASK (0x3f << 24)
#define SMIDSW_WSETUP_MASK (0x3f << 24)DMA_THRESHOLD_BYTES
#define SMIDSW_WSETUP_OFFS (24)
#define SMIDSW_WFORMAT (1 << 23)
#define SMIDSW_WSWAP (1 << 22)

Wyświetl plik

@ -0,0 +1,125 @@
# SMI Kernel Module
**Based on a doc. written By Michael Bishop - @CleverCa22 @ "https://github.com/librerpi/rpi-open-firmware"**
- "brcm,bcm2835-smi-dev" - creates a character device, smi_handle must point to the main smi instance
- "brcm,bcm2835-smi" - the main smi instance
In the default mode, there are separate read and write strobes, called SOE and SWE. when the **bus is idle, the rpi will drive the data pins low**.
During the setup SETUP period the strobe is high, and the address pins are presented. Then, if its a read operation, the data pins will switch to input mode at the start of SETUP. If its a write operation, the data will be presented on the data pins.
Then there is the STROBE phase, when either SOE or SWE goes low. For a read (SOE), the rpi will sample the data pins at the end of STROBE.
The HOLD phase just to let the lines settle after after strobe has been released. In the default mode, it does 16bit transfers.
If the full packet is an even multiple of 32bits (4 bytes), then the RPI can use dma to burst the whole thing, with just setup + strobe + hold clocks per 16bit (or 8-bits) transfer. If there is a stray 16bits at the end, the dma will do a dense burst with dma, but then do the stray 16bit seperately a while later
# SMI Clock
and from arch/arm/boot/dts/bcm270x.dtsi
```
Code: Select all
smi: smi@7e600000 {
...
assigned-clocks = <&clocks BCM2835_CLOCK_SMI>;
assigned-clock-rates = <125000000>;
```
Here we can see that the DTS sets the default clock of 125MHz to the SMI operation.
## Register SMI_CS (0x00) - Control + Status
| Bit | Name | Description
|-----|-------|-----------|
|0 | ENABLE||
|1 | DONE | returns 1 when done|
|2 | ACTIVE | returns 1 when doing a transfer
|3 | START | write 1 to start transfer
|4 | CLEAR | write 1 to clear fifo
|5 | WRITE | direction, 1=write, 0=read
|6:7 | PAD | for write, drop the first $PAD bytes in the fifo, for read, drop $PAD bytes from hw, before filling fifo
|8 | TEEN | tear effect mode enabled, transfers will wait for TE trigger
|9 | INTD | interrupt when done
|10 | INTT | interrupt on tx
|11 | INTR | interrupt on rx
|12 | PVMODE | enable pixelvalve mode
|13 | SETERR | write 1 to clear, turns 1 to signal a change to timing while ACTIVE
|14 | PXLDAT | enable pixel transfer modes
|15 | EDREQ | signals an external DREQ level
|24 | TBD| pixel ready?
|25 | TBD| axi fifo error, set to 1 to clear, sets itself if you read fifo when empty, or write fifo when full
|26 | TBD| tx fifo needs writing (under 1/4ths full)
|27 | TBD| rx fifo needs reading (either 3/4ths full, or DONE and not empty)
|28 | TBD| tx fifo has room
|29 | TBD| rx fifo contains data
|30 | TBD| tx fifo empty
|31 | TBD| rx fifo full
## Register SMI_L (0x04) - length / count
TBD
## Register SMI_A (0x08) - address
| bits | Name | Description|
|--|--|--|
| 0:5| TBD| address|
8:9|TBD| device address|
## Register SMI_D 0x0c data
SMI_DSR0 0x10 device0 read settings
SMI_DSW0 0x14 device0 write settings
SMI_DSR1 0x18 device1 read
SMI_DSW1 0x1c device1 write
SMI_DSR2 0x20
SMI_DSW2 0x24
SMI_DSR3 0x28
SMI_DSW3 0x2c
settings:
0:6 strobe 0-127 clock cycles to assert strobe
7 dreq use external dma request on sd16 to pace reads from device, sd17 to pace writes
8:14 pace clock cycles to wait between CS deassertion and start of next xfer
15 paceall if 1, use the PACE value, even if the next device is different
16:21 hold 0-63 clock cycles between strobe going inactive and cs/addr going inactive
22 read:fsetup 1: setup time only on first xfer after addr change, write: wswap(swap pixel data bits)
23 read:mode68 0:(oe+we) 1:(enable+dir), write: wformat(0=rgb565, 1=32bit rgba8888)
24:29 setup, clock cycles between chipselect/address, and read/write strobe
30:31 width, 00=8bit, 01==16bit, 10=18bit, 11=9bit
SMI_DC 0x30 dma control registers
24 dma passthru
28 dma enable
SMI_DCS 0x34 direct control/status register
0 ENABLE
1 START
2 DONE
3 WRITE
SMI_DA 0x38 direct address register
0:5 addr
8:9 device
SMI_DD 0x3c direct data registers
SMI_FD 0x40 FIFO debug register
0:5 FCNT current fifo count
8:13 FLVL high tide mark of FIFO count during most recent xfer
notes from experiments done with /dev/smi
the dma on the rpi can only send/recv 32bit chunks to the SMI (see drivers/char/broadcom/bcm2835_smi_dev.c odd_bytes)
any extra has to be sent as a second transaction? with an variable delay after the main burst
the main burst can operate at max speed with very dense packing
a burst involves a repeating setup, strobe, hold, setup, strobe, hold cycle
a burst is always followed by a pace period?
SOE goes low during the strobe period of a read?
the default smi clock on a pi0 is about 125mhz (cat /sys/kernel/debug/clk/smi/clk_rate)
bcm270x.dtsi defines the `assigned-clock-rates` to 125mhz
SA is held during at least strobe and hold, but vanishes during pace, bcm2835_smi.h claims its held during pace!!
during a read, SD0-SD17 are tristated at the start of SETUP, then driven low at the end of HOLD
during a read, SD0-SD17 are sampled at the end of STROBE
if 2 READ's occur back to back, the end of HOLD is the start of SETUP, and SD0-SD17 remain tri-state
in the default mode, SOE will strobe during reads, SWE strobes during writes

Wyświetl plik

@ -0,0 +1,87 @@
#include "bcm2835_smi.h"
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <unistd.h>
static void fail(const char *msg) {
perror(msg);
exit(1);
}
static void print_smi_settings(struct smi_settings *settings) {
printf("width: %d\n", settings->data_width);
printf("pack: %c\n", settings->pack_data ? 'Y' : 'N');
printf("read setup: %d, strobe: %d, hold: %d, pace: %d\n", settings->read_setup_time, settings->read_strobe_time, settings->read_hold_time, settings->read_pace_time);
printf("write setup: %d, strobe: %d, hold: %d, pace: %d\n", settings->write_setup_time, settings->write_strobe_time, settings->write_hold_time, settings->write_pace_time);
printf("dma enable: %c, passthru enable: %c\n", settings->dma_enable ? 'Y':'N', settings->dma_passthrough_enable ? 'Y':'N');
printf("dma threshold read: %d, write: %d\n", settings->dma_read_thresh, settings->dma_write_thresh);
printf("dma panic threshold read: %d, write: %d\n", settings->dma_panic_read_thresh, settings->dma_panic_write_thresh);
}
int main(int argc, char **argv) {
int count = 8;
int opt;
int fd = open("/dev/smi", O_RDWR);
if (fd < 0) fail("cant open");
struct smi_settings settings;
int ret = ioctl(fd, BCM2835_SMI_IOC_GET_SETTINGS, &settings);
if (ret != 0) fail("ioctl 1");
settings.read_setup_time = 10;
settings.read_strobe_time = 20;
settings.read_hold_time = 40;
settings.read_pace_time = 80;
bool writeMode = false;
while ((opt = getopt(argc, argv, "b:e:s:h:p:wE:S:H:P:")) != -1) {
switch (opt) {
case 'b':
count = atoi(optarg);
break;
case 'e':
settings.read_setup_time = atoi(optarg);
break;
case 's':
settings.read_strobe_time = atoi(optarg);
break;
case 'h':
settings.read_hold_time = atoi(optarg);
break;
case 'p':
settings.read_pace_time = atoi(optarg);
break;
case 'E':
settings.write_setup_time = atoi(optarg);
break;
case 'S':
settings.write_strobe_time = atoi(optarg);
break;
case 'H':
settings.write_hold_time = atoi(optarg);
break;
case 'P':
settings.write_pace_time = atoi(optarg);
break;
case 'w':
writeMode = true;
break;
}
}
ret = ioctl(fd, BCM2835_SMI_IOC_WRITE_SETTINGS, &settings);
if (ret != 0) fail("ioctl 2");
print_smi_settings(&settings);
uint16_t buffer[count];
if (writeMode) {
for (int i=0; i<count; i++) buffer[i] = i;
write(fd, buffer, count*2);
} else {
read(fd, buffer, count*2);
for (int i=0; i<count; i++) printf("%02x ", buffer[i]);
puts("\n");
}
}

Wyświetl plik

@ -40,13 +40,13 @@ typedef enum
typedef enum
{
caribou_smi_address_idle = 0,
caribou_smi_address_read_900 = 1,
caribou_smi_address_read_2400 = 2,
caribou_smi_address_read_res = 3,
caribou_smi_address_write_res1 = 4,
caribou_smi_address_write_900 = 5,
caribou_smi_address_write_2400 = 6,
caribou_smi_address_write_res2 = 7,
caribou_smi_address_write_900 = 1,
caribou_smi_address_write_2400 = 2,
caribou_smi_address_write_res2 = 3,
caribou_smi_address_read_res1 = 4,
caribou_smi_address_read_900 = 5,
caribou_smi_address_read_2400 = 6,
caribou_smi_address_read_res = 7,
} caribou_smi_address_en;
typedef enum