Pi Firmware: Test build for issue 1022

Change-Id: I49a18b786aabfdc46747a019a75a333f01790594
issue_1022
David Banks 2018-07-21 09:49:06 +01:00
rodzic 695249b650
commit 1d1ed94aac
8 zmienionych plików z 10 dodań i 1116 usunięć

Wyświetl plik

@ -61,17 +61,12 @@ file( GLOB core_files
armc-cstartup.c
armc-cstubs.c
rgb_to_hdmi.c
rgb_to_fb.S
defs.h
arm-exception.c
cache.c
cache.h
rpi-gpio.c
rpi-gpio.h
rpi-aux.c
rpi-aux.h
rpi-interrupts.c
rpi-interrupts.h
rpi-mailbox.c
rpi-mailbox.h
rpi-mailbox-interface.c
@ -80,15 +75,6 @@ file( GLOB core_files
info.h
logging.c
logging.h
cpld.h
cpld_normal.h
cpld_normal.c
cpld_alternative.h
cpld_alternative.c
osd.h
osd.c
saa5050_font.h
saa5050_font.c
)

Wyświetl plik

@ -1,782 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include "cache.h"
#include "defs.h"
#include "cpld.h"
#include "rpi-aux.h"
#include "rpi-mailbox-interface.h"
#include "info.h"
#include "logging.h"
#include "rpi-aux.h"
#include "rpi-gpio.h"
#include "rpi-mailbox-interface.h"
#include "startup.h"
#include "rpi-mailbox.h"
#include "osd.h"
#include "cpld.h"
#include "cpld_normal.h"
#include "cpld_alternative.h"
// #define INSTRUMENT_CAL
#define NUM_CAL_PASSES 1
#define SHORT_PRESS 0
#define LONG_PRESS 1
#ifdef DOUBLE_BUFFER
#include "rpi-interrupts.h"
#endif
typedef void (*func_ptr)();
#define GZ_CLK_BUSY (1 << 7)
#define GP_CLK1_CTL (volatile uint32_t *)(PERIPHERAL_BASE + 0x101078)
#define GP_CLK1_DIV (volatile uint32_t *)(PERIPHERAL_BASE + 0x10107C)
// =============================================================
// Global variables
// =============================================================
cpld_t *cpld = NULL;
unsigned char *fb = NULL;
int pitch = 0;
int clock_error_ppm = 0;
// =============================================================
// Local variables
// =============================================================
static int width = 0;
static int height = 0;
static uint32_t cpld_version_id;
static volatile int delay;
static int elk;
static int mode7;
static int clear;
static int scanlines = 0;
static int last_mode7;
static int result;
static int chars_per_line;
// TODO: Don't hardcode pitch!
static unsigned char last[SCREEN_HEIGHT * 336] __attribute__((aligned(32)));
#ifndef USE_PROPERTY_INTERFACE_FOR_FB
typedef struct {
uint32_t width;
uint32_t height;
uint32_t virtual_width;
uint32_t virtual_height;
volatile uint32_t pitch;
volatile uint32_t depth;
uint32_t x_offset;
uint32_t y_offset;
volatile uint32_t pointer;
volatile uint32_t size;
} framebuf;
// The + 0x10000 is to miss the property buffer
static framebuf *fbp = (framebuf *) (UNCACHED_MEM_BASE + 0x10000);
#endif
// =============================================================
// External symbols from rgb_to_fb.S
// =============================================================
extern int rgb_to_fb(unsigned char *fb, int chars_per_line, int bytes_per_line, int mode7);
extern int measure_vsync();
// =============================================================
// Private methods
// =============================================================
// 0 0 Hz Ground
// 1 19.2 MHz oscillator
// 2 0 Hz testdebug0
// 3 0 Hz testdebug1
// 4 0 Hz PLLA
// 5 1000 MHz PLLC (changes with overclock settings)
// 6 500 MHz PLLD
// 7 216 MHz HDMI auxiliary
// 8-15 0 Hz Ground
// Source 1 = OSC = 19.2MHz
// Source 4 = PLLA = 0MHz
// Source 5 = PLLC = core_freq * 3 = (384 * 3) = 1152
// Source 6 = PLLD = 500MHz
static void init_gpclk(int source, int divisor) {
log_debug("A GP_CLK1_DIV = %08"PRIx32, *GP_CLK1_DIV);
log_debug("B GP_CLK1_CTL = %08"PRIx32, *GP_CLK1_CTL);
// Stop the clock generator
*GP_CLK1_CTL = 0x5a000000 | source;
// Wait for BUSY low
log_debug("C GP_CLK1_CTL = %08"PRIx32, *GP_CLK1_CTL);
while ((*GP_CLK1_CTL) & GZ_CLK_BUSY) {}
log_debug("D GP_CLK1_CTL = %08"PRIx32, *GP_CLK1_CTL);
// Configure the clock generator
*GP_CLK1_DIV = 0x5A000000 | (divisor << 12);
*GP_CLK1_CTL = 0x5A000000 | source;
log_debug("E GP_CLK1_CTL = %08"PRIx32, *GP_CLK1_CTL);
// Start the clock generator
*GP_CLK1_CTL = 0x5A000010 | source;
log_debug("F GP_CLK1_CTL = %08"PRIx32, *GP_CLK1_CTL);
while (!((*GP_CLK1_CTL) & GZ_CLK_BUSY)) {} // Wait for BUSY high
log_debug("G GP_CLK1_CTL = %08"PRIx32, *GP_CLK1_CTL);
log_debug("H GP_CLK1_DIV = %08"PRIx32, *GP_CLK1_DIV);
}
#ifdef USE_PROPERTY_INTERFACE_FOR_FB
static void init_framebuffer(int mode7) {
rpi_mailbox_property_t *mp;
int w = mode7 ? SCREEN_WIDTH_MODE7 : SCREEN_WIDTH_MODE06;
/* Initialise a framebuffer... */
RPI_PropertyInit();
RPI_PropertyAddTag( TAG_ALLOCATE_BUFFER );
RPI_PropertyAddTag( TAG_SET_PHYSICAL_SIZE, w, SCREEN_HEIGHT );
#ifdef DOUBLE_BUFFER
RPI_PropertyAddTag( TAG_SET_VIRTUAL_SIZE, w, SCREEN_HEIGHT * 2 );
#else
RPI_PropertyAddTag( TAG_SET_VIRTUAL_SIZE, w, SCREEN_HEIGHT );
#endif
RPI_PropertyAddTag( TAG_SET_DEPTH, SCREEN_DEPTH );
if (SCREEN_DEPTH <= 8) {
RPI_PropertyAddTag( TAG_SET_PALETTE, osd_get_palette());
}
RPI_PropertyAddTag( TAG_GET_PITCH );
RPI_PropertyAddTag( TAG_GET_PHYSICAL_SIZE );
RPI_PropertyAddTag( TAG_GET_DEPTH );
RPI_PropertyProcess();
// FIXME: A small delay (like the log) is neccessary here
// or the RPI_PropertyGet seems to return garbage
log_info( "Initialised Framebuffer" );
if( ( mp = RPI_PropertyGet( TAG_GET_PHYSICAL_SIZE ) ) )
{
width = mp->data.buffer_32[0];
height = mp->data.buffer_32[1];
log_info( "Size: %dx%d ", width, height );
}
if( ( mp = RPI_PropertyGet( TAG_GET_PITCH ) ) )
{
pitch = mp->data.buffer_32[0];
log_info( "Pitch: %d bytes", pitch );
}
if( ( mp = RPI_PropertyGet( TAG_ALLOCATE_BUFFER ) ) )
{
fb = (unsigned char*)mp->data.buffer_32[0];
log_info( "Framebuffer address: %8.8X", (unsigned int)fb );
}
// On the Pi 2/3 the mailbox returns the address with bits 31..30 set, which is wrong
fb = (unsigned char *)(((unsigned int) fb) & 0x3fffffff);
}
#else
// An alternative way to initialize the framebuffer using mailbox channel 1
//
// I was hoping it would then be possible to page flip just by modifying the structure
// in-place. Unfortunately that didn't work, but the code might be useful in the future.
static void init_framebuffer(int mode7) {
log_info( "Framebuf struct address: %p", fbp );
int w = mode7 ? SCREEN_WIDTH_MODE7 : SCREEN_WIDTH_MODE06;
// Fill in the frame buffer structure
fbp->width = w;
fbp->height = SCREEN_HEIGHT;
fbp->virtual_width = w;
#ifdef DOUBLE_BUFFER
fbp->virtual_height = SCREEN_HEIGHT * 2;
#else
fbp->virtual_height = SCREEN_HEIGHT;
#endif
fbp->pitch = 0;
fbp->depth = SCREEN_DEPTH;
fbp->x_offset = 0;
fbp->y_offset = 0;
fbp->pointer = 0;
fbp->size = 0;
// Send framebuffer struct to the mailbox
//
// The +0x40000000 ensures the GPU bypasses it's cache when accessing
// the framebuffer struct. If this is not done, the screen still initializes
// but the ARM doesn't see the updated value for a very long time
// i.e. the commented out section of code below is needed, and this eventually
// exits with i=4603039
//
// 0xC0000000 should be added if disable_l2cache=1
RPI_Mailbox0Write(MB0_FRAMEBUFFER, ((unsigned int)fbp) + 0xC0000000 );
// Wait for the response (0)
RPI_Mailbox0Read( MB0_FRAMEBUFFER );
pitch = fbp->pitch;
fb = (unsigned char*)(fbp->pointer);
width = fbp->width;
height = fbp->height;
// See comment above
// int i = 0;
// while (!pitch || !fb) {
// pitch = fbp->pitch;
// fb = (unsigned char*)(fbp->pointer);
// i++;
// }
// log_info( "i=%d", i);
log_info( "Initialised Framebuffer: %dx%d ", width, height );
log_info( "Pitch: %d bytes", pitch );
log_info( "Framebuffer address: %8.8X", (unsigned int)fb );
// Initialize the palette
if (SCREEN_DEPTH <= 8) {
RPI_PropertyInit();
RPI_PropertyAddTag( TAG_SET_PALETTE, osd_get_palette());
RPI_PropertyProcess();
}
// On the Pi 2/3 the mailbox returns the address with bits 31..30 set, which is wrong
fb = (unsigned char *)(((unsigned int) fb) & 0x3fffffff);
}
#endif
static int calibrate_clock() {
int a = 13;
unsigned int frame_ref;
log_info(" Nominal clock = %d Hz", CORE_FREQ);
unsigned int frame_time = measure_vsync();
if (frame_time & INTERLACED_FLAG) {
frame_ref = 40000000;
log_info("Nominal frame time = %d ns (interlaced)", frame_ref);
} else {
frame_ref = 40000000 - 64000;
log_info("Nominal frame time = %d ns (non-interlaced)", frame_ref);
}
frame_time &= ~INTERLACED_FLAG;
log_info(" Actual frame time = %d ns", frame_time);
double error = (double) frame_time / (double) frame_ref;
clock_error_ppm = ((error - 1.0) * 1e6);
log_info(" Frame time error = %d PPM", clock_error_ppm );
int new_clock = (int) (((double) CORE_FREQ) / error);
log_info(" Optimal clock = %d Hz", new_clock);
// Sanity check clock
if (new_clock < 380000000 || new_clock > 388000000) {
log_info("Clock out of range 380MHz-388MHz, defaulting to 384MHz");
new_clock = CORE_FREQ;
}
// Wait a while to allow UART time to empty
for (delay = 0; delay < 100000; delay++) {
a = a * 13;
}
// Switch to new core clock speed
RPI_PropertyInit();
RPI_PropertyAddTag( TAG_SET_CLOCK_RATE, CORE_CLK_ID, new_clock, 1);
RPI_PropertyProcess();
// Re-initialize UART, as system clock rate changed
RPI_AuxMiniUartInit( 115200, 8 );
// Check the new clock
int actual_clock = get_clock_rate(CORE_CLK_ID);
log_info(" Final clock = %d Hz", actual_clock);
return a;
}
static void init_hardware() {
int i;
for (i = 0; i < 12; i++) {
RPI_SetGpioPinFunction(PIXEL_BASE + i, FS_INPUT);
}
RPI_SetGpioPinFunction(PSYNC_PIN, FS_INPUT);
RPI_SetGpioPinFunction(CSYNC_PIN, FS_INPUT);
RPI_SetGpioPinFunction(SW1_PIN, FS_INPUT);
RPI_SetGpioPinFunction(SW2_PIN, FS_INPUT);
RPI_SetGpioPinFunction(SW3_PIN, FS_INPUT);
RPI_SetGpioPinFunction(SPARE_PIN, FS_INPUT);
RPI_SetGpioPinFunction(VERSION_PIN, FS_OUTPUT);
RPI_SetGpioPinFunction(MODE7_PIN, FS_OUTPUT);
RPI_SetGpioPinFunction(MUX_PIN, FS_OUTPUT);
RPI_SetGpioPinFunction(SP_CLK_PIN, FS_OUTPUT);
RPI_SetGpioPinFunction(SP_DATA_PIN, FS_OUTPUT);
RPI_SetGpioPinFunction(SP_CLKEN_PIN, FS_OUTPUT);
RPI_SetGpioPinFunction(LED1_PIN, FS_OUTPUT);
RPI_SetGpioValue(VERSION_PIN, 1);
RPI_SetGpioValue(MODE7_PIN, 1);
RPI_SetGpioValue(MUX_PIN, 0);
RPI_SetGpioValue(SP_CLK_PIN, 1);
RPI_SetGpioValue(SP_DATA_PIN, 0);
RPI_SetGpioValue(SP_CLKEN_PIN, 0);
RPI_SetGpioValue(LED1_PIN, 0); // active high
#ifdef DOUBLE_BUFFER
// This line enables IRQ interrupts
// Enable smi_int which is IRQ 48
// https://github.com/raspberrypi/firmware/issues/67
RPI_GetIrqController()->Enable_IRQs_2 = (1 << VSYNCINT);
#endif
// Initialize hardware cycle counter
_init_cycle_counter();
// Configure the GPCLK pin as a GPCLK
RPI_SetGpioPinFunction(GPCLK_PIN, FS_ALT5);
// The divisor us now the same for both modes
log_debug("Setting up divisor");
init_gpclk(GPCLK_SOURCE, DEFAULT_GPCLK_DIVISOR);
log_debug("Done setting up divisor");
// Measure the frame time and set a clock to 384MHz +- the error
calibrate_clock();
// Initialise the info system with cached values (as we break the GPU property interface)
init_info();
#ifdef DEBUG
dump_useful_info();
#endif
}
static void cpld_init() {
// Assert the active low version pin
RPI_SetGpioValue(VERSION_PIN, 0);
// The CPLD now outputs a identifier and version number on the 12-bit pixel quad bus
cpld_version_id = 0;
for (int i = PIXEL_BASE + 11; i >= PIXEL_BASE; i--) {
cpld_version_id <<= 1;
cpld_version_id |= RPI_GetGpioValue(i) & 1;
}
// Release the active low version pin
RPI_SetGpioValue(VERSION_PIN, 1);
// Set the appropriate cpld "driver" based on the version
if ((cpld_version_id >> VERSION_DESIGN_BIT) == DESIGN_NORMAL) {
cpld = &cpld_normal;
} else if ((cpld_version_id >> VERSION_DESIGN_BIT) == DESIGN_ALTERNATIVE) {
cpld = &cpld_alternative;
} else {
log_info("Unknown CPLD: identifier = %03x", cpld_version_id);
log_info("Halting\n");
while (1);
}
log_info("CPLD Design: %s", cpld->name);
log_info("CPLD Version: %x.%x", (cpld_version_id >> VERSION_MAJOR_BIT) & 0x0f, (cpld_version_id >> VERSION_MINOR_BIT) & 0x0f);
// Initialize the CPLD's default sampling points
cpld->init();
}
static int test_for_elk(int elk, int mode7, int chars_per_line) {
// If mode 7, then assume the Beeb
if (mode7) {
// Leave the setting unchanged
return elk;
}
unsigned int ret;
unsigned int flags = BIT_CALIBRATE | BIT_CAL_COUNT;
// Grab one field
ret = rgb_to_fb(fb, chars_per_line, pitch, flags);
unsigned char *fb1 = fb + ((ret & BIT_LAST_BUFFER) ? SCREEN_HEIGHT * pitch : 0);
// Grab second field
ret = rgb_to_fb(fb, chars_per_line, pitch, flags);
unsigned char *fb2 = fb + ((ret & BIT_LAST_BUFFER) ? SCREEN_HEIGHT * pitch : 0);
if (fb1 == fb2) {
log_warn("test_for_elk() failed, both buffers the same!");
// Leave the setting unchanged
return elk;
}
unsigned int min_diff = INT_MAX;
unsigned int min_offset = 0;
for (int offset = -2; offset <= 2; offset += 2) {
uint32_t *p1 = (uint32_t *)(fb1 + 2 * pitch);
uint32_t *p2 = (uint32_t *)(fb2 + 2 * pitch + offset * pitch);
unsigned int diff = 0;
for (int i = 0; i < (SCREEN_HEIGHT - 4) * pitch; i += 4) {
uint32_t d = (*p1++) ^ (*p2++);
while (d) {
if (d & 0x0F) {
diff++;
}
d >>= 4;
}
}
if (diff < min_diff) {
min_diff = diff;
min_offset = offset;
}
log_debug("offset = %d, diff = %u", offset, diff);
}
log_debug("min offset = %d", min_offset);
return min_offset != 0;
}
#ifdef HAS_MULTICORE
static void start_core(int core, func_ptr func) {
printf("starting core %d\r\n", core);
*(unsigned int *)(0x4000008C + 0x10 * core) = (unsigned int) func;
}
#endif
// =============================================================
// Public methods
// =============================================================
int *diff_N_frames(int n, int mode7, int elk, int chars_per_line) {
unsigned int ret;
static int sum[3];
static int min[3];
static int max[3];
static int diff[3];
for (int i = 0; i < 3; i++) {
sum[i] = 0;
min[i] = INT_MAX;
max[i] = INT_MIN;
}
#ifdef INSTRUMENT_CAL
unsigned int t;
unsigned int t_capture = 0;
unsigned int t_memcpy = 0;
unsigned int t_compare = 0;
#endif
// In mode 0..6, set BIT_CAL_COUNT to 1 (capture 1 field)
// In mode 7, set BIT_CAL_COUNT to 0 (capture two fields, doesn't matter whether odd-even or even-odd)
unsigned int flags = mode7 | BIT_CALIBRATE | (mode7 ? 0 : BIT_CAL_COUNT) | ((elk & !mode7) ? BIT_ELK : 0);
#ifdef INSTRUMENT_CAL
t = _get_cycle_counter();
#endif
// Grab an initial frame
ret = rgb_to_fb(fb, chars_per_line, pitch, flags);
#ifdef INSTRUMENT_CAL
t_capture += _get_cycle_counter() - t;
#endif
for (int i = 0; i < n; i++) {
diff[0] = 0;
diff[1] = 0;
diff[2] = 0;
#ifdef INSTRUMENT_CAL
t = _get_cycle_counter();
#endif
// Save the last frame
memcpy((void *)last, (void *)(fb + ((ret & BIT_LAST_BUFFER) ? SCREEN_HEIGHT * pitch : 0)), SCREEN_HEIGHT * pitch);
#ifdef INSTRUMENT_CAL
t_memcpy += _get_cycle_counter() - t;
t = _get_cycle_counter();
#endif
// Grab the next frame
ret = rgb_to_fb(fb, chars_per_line, pitch, flags);
#ifdef INSTRUMENT_CAL
t_capture += _get_cycle_counter() - t;
t = _get_cycle_counter();
#endif
// Compare the frames
uint32_t *fbp = (uint32_t *)(fb + ((ret & BIT_LAST_BUFFER) ? SCREEN_HEIGHT * pitch : 0));
uint32_t *lastp = (uint32_t *)last;
for (int line = 0; line < SCREEN_HEIGHT; line++) {
int skip = 0;
// Skip lines that might contain flashing cursor
// (the cursor rows were determined empirically)
if (elk) {
// Eliminate cursor lines in 32 row modes (0,1,2,4,5)
if (!mode7 && ((line >> 1) % 8) == 5) {
skip = 1;
}
// Eliminate cursor lines in 25 row modes (3, 6)
if (!mode7 && ((line >> 1) % 10) == 3) {
skip = 1;
}
// Eliminate cursor lines in mode 7
// (this case is untested as I don't have a Jafa board)
if (mode7 && ((line % 20) == 13 || (line % 20) == 14)) {
skip = 1;
}
} else {
// Eliminate cursor lines in 32 row modes (0,1,2,4,5)
if (!mode7 && ((line >> 1) % 8) == 7) {
skip = 1;
}
// Eliminate cursor lines in 25 row modes (3, 6)
if (!mode7 && ((line >> 1) % 10) >= 5 && ((line >> 1) % 10) <= 7) {
skip = 1;
}
// Eliminate cursor lines in mode 7
if (mode7 && ((line % 20) == 13 || (line % 20) == 14)) {
skip = 1;
}
}
if (skip) {
// For debugging it's useful to see if the lines being eliminated align with the cursor
// for (int x = 0; x < pitch; x += 4) {
// *fbp++ = 0x11111111;
// }
fbp += pitch >> 2;
lastp += pitch >> 2;
} else {
for (int x = 0; x < pitch; x += 4) {
uint32_t d = (*fbp++) ^ (*lastp++);
// Mask out OSD
d &= 0x77777777;
while (d) {
if (d & 0x01) {
diff[0]++;
}
if (d & 0x02) {
diff[1]++;
}
if (d & 0x04) {
diff[2]++;
}
d >>= 4;
}
}
}
}
#ifdef INSTRUMENT_CAL
t_compare += _get_cycle_counter() - t;
#endif
// Accumulate the result
for (int j = 0; j < 3; j++) {
sum[j] += diff[j];
if (diff[j] < min[j]) {
min[j] = diff[j];
}
if (diff[j] > max[j]) {
max[j] = diff[j];
}
}
}
#if 0
for (int j = 0; j < 3; j++) {
int mean = sum[j] / n;
log_debug("channel %d: diff: sum = %d mean = %d, min = %d, max = %d", j, sum[j], mean, min[j], max[j]);
}
#endif
#ifdef INSTRUMENT_CAL
log_debug("t_capture total = %d, mean = %d ", t_capture, t_capture / (n + 1));
log_debug("t_compare total = %d, mean = %d ", t_compare, t_compare / n);
log_debug("t_memcpy total = %d, mean = %d ", t_memcpy, t_memcpy / n);
log_debug("total = %d", t_capture + t_compare + t_memcpy);
#endif
return sum;
}
#if 0
int total_N_frames(int n, int mode7, int elk, int chars_per_line) {
int sum = 0;
int min = INT_MAX;
int max = INT_MIN;
#ifdef INSTRUMENT_CAL
unsigned int t;
unsigned int t_capture = 0;
unsigned int t_compare = 0;
#endif
// In mode 0..6, set BIT_CAL_COUNT to 1 (capture 1 field)
// In mode 7, set BIT_CAL_COUNT to 0 (capture two fields, doesn't matter whether odd-even or even-odd)
unsigned int flags = mode7 | BIT_CALIBRATE | (mode7 ? 0 : BIT_CAL_COUNT) | ((elk & !mode7) ? BIT_ELK : 0);
for (int i = 0; i < n; i++) {
int total = 0;
// Grab the next frame
ret = rgb_to_fb(fb, chars_per_line, pitch, flags);
#ifdef INSTRUMENT_CAL
t_capture += _get_cycle_counter() - t;
t = _get_cycle_counter();
#endif
// Compare the frames
uint32_t *fbp = (uint32_t *)(fb + ((ret & BIT_LAST_BUFFER) ? SCREEN_HEIGHT * pitch : 0));
for (int j = 0; j < SCREEN_HEIGHT * pitch; j += 4) {
uint32_t f = *fbp++;
// Mask out OSD
f &= 0x77777777;
while (f) {
if (f & 0x0F) {
total++;
}
f >>= 4;
}
}
#ifdef INSTRUMENT_CAL
t_compare += _get_cycle_counter() - t;
#endif
// Accumulate the result
sum += total;
if (total < min) {
min = total;
}
if (total > max) {
max = total;
}
}
int mean = sum / n;
log_debug("total: sum = %d mean = %d, min = %d, max = %d", sum, mean, min, max);
#ifdef INSTRUMENT_CAL
log_debug("t_capture total = %d, mean = %d ", t_capture, t_capture / (n + 1));
log_debug("t_compare total = %d, mean = %d ", t_compare, t_compare / n);
log_debug("total = %d", t_capture + t_compare + t_memcpy);
#endif
return sum;
}
#endif
#ifdef DOUBLE_BUFFER
void swapBuffer(int buffer) {
// Flush the previous response from the GPU->ARM mailbox
// Doing it like this avoids stalling for the response
RPI_Mailbox0Flush( MB0_TAGS_ARM_TO_VC );
RPI_PropertyInit();
if (buffer) {
RPI_PropertyAddTag( TAG_SET_VIRTUAL_OFFSET, 0, SCREEN_HEIGHT);
} else {
RPI_PropertyAddTag( TAG_SET_VIRTUAL_OFFSET, 0, 0);
}
// Use version that doesn't wait for the response
RPI_PropertyProcessNoCheck();
}
#endif
void set_elk(int on) {
elk = on;
clear = BIT_CLEAR;
}
int get_elk() {
return elk;
}
void action_scanlines(int on) {
if (on) {
scanlines = BIT_SCANLINES;
} else {
scanlines = 0;
}
clear = BIT_CLEAR;
}
void action_calibrate() {
// During calibration we do our best to auto-delect an Electron
elk = test_for_elk(elk, mode7, chars_per_line);
log_debug("Elk mode = %d", elk);
for (int c = 0; c < NUM_CAL_PASSES; c++) {
cpld->calibrate(elk, chars_per_line);
}
}
void rgb_to_hdmi_main() {
// Initialize the cpld after the gpclk generator has been started
cpld_init();
// Initialize the On-Screen Display
osd_init();
// Determine initial mode
mode7 = rgb_to_fb(fb, 0, 0, BIT_PROBE) & BIT_MODE7;
while (1) {
log_debug("Setting mode7 = %d", mode7);
RPI_SetGpioValue(MODE7_PIN, mode7);
log_debug("Setting up frame buffer");
init_framebuffer(mode7);
log_debug("Done setting up frame buffer");
log_debug("Loading sample points");
cpld->set_mode(mode7);
log_debug("Done loading sample points");
chars_per_line = mode7 ? MODE7_CHARS_PER_LINE : DEFAULT_CHARS_PER_LINE;
clear = BIT_CLEAR;
osd_refresh();
do {
log_debug("Entering rgb_to_fb");
result = rgb_to_fb(fb, chars_per_line, pitch, mode7 | BIT_INITIALIZE | ((elk & !mode7) ? BIT_ELK : 0) | clear | scanlines);
log_debug("Leaving rgb_to_fb, result=%04x", result);
clear = 0;
if (result & RET_SW1) {
osd_key(OSD_SW1);
}
if (result & RET_SW2) {
osd_key(OSD_SW2);
}
if (result & RET_SW3) {
osd_key(OSD_SW3);
}
last_mode7 = mode7;
mode7 = result & BIT_MODE7;
} while (mode7 == last_mode7);
osd_clear();
}
}
void kernel_main(unsigned int r0, unsigned int r1, unsigned int atags)
{
@ -784,24 +9,13 @@ void kernel_main(unsigned int r0, unsigned int r1, unsigned int atags)
log_info("RGB to HDMI booted");
init_hardware();
// Switch to new core clock speed
RPI_PropertyInit();
RPI_PropertyAddTag( TAG_SET_CLOCK_RATE, CORE_CLK_ID, 384123456, 1);
RPI_PropertyProcess();
enable_MMU_and_IDCaches();
_enable_unaligned_access();
dump_useful_info();
#ifdef HAS_MULTICORE
int i;
printf("main running on core %d\r\n", _get_core());
for (i = 0; i < 10000000; i++);
start_core(1, _spin_core);
for (i = 0; i < 10000000; i++);
start_core(2, _spin_core);
for (i = 0; i < 10000000; i++);
start_core(3, _spin_core);
for (i = 0; i < 10000000; i++);
#endif
rgb_to_hdmi_main();
while(1);
}

Wyświetl plik

@ -1,63 +0,0 @@
# ======================================================================
# cmdline.txt file for RGBtoHDMI (https://github.com/hoglet67/RGBtoHDMI)
# ======================================================================
#
# sampling06: Sample points for modes 0..6
# - Specify a single value here, in the range 0..5
#
# The sampling06 value can be copied from the Calibration Summary screen:
# - Select Mode 6 screen
# - Type *HELP to get some text on the screen
# - Press Auto Calibation (right button)
# - Select: Feature Menu/Info/Calibration Summary
# - Use the value of the "Offset" (all should be the same)
#
# sampling7: Sample points for mode 7
# - Specify eight comma seperated values: 0,A,B,C,D,E,F,Half
# -- or --
# - Specify a single value here, in the range 0..7
#
# The sampling7 values can be copied from the Calibration Summary screen:
# - Select Mode 7 screen
# - Type *HELP to get some text on the screen
# - Press Auto Calibation (right button)
# - Select: Feature Menu/Info/Calibration Summary
# - For A..F use the six "Offset" values
# - For H use the "Half" value
#
# info: the default info screen
# - 0 is the firmware version
# - 1 is the calibration summary
# - 2 is the calibration detail
#
# palette: colour palette number
# - 0 is Default
# - 1 is Inverse
# - 2 is Mono 1
# - 3 is Mono 2
# - 4 is Just Red
# - 5 is Just Green
# - 6 is Just Blue
# - 7 is Not Red
# - 8 is Not Green
# - 9 is Not Blue
#
# scalines: show visible scanlines in modes 0..6
# - 0 is scanlines off
# - 1 is scanlines on
#
# mux: initial setting of the input mux
# - 0 is direct
# - 1 is via the 74LS08 buffer (for Issue 2/4 Elk only)
#
# elk: indicates the interface is connected to an elk
# - 0 is Model B/Master
# - 1 is Elk
#
# debug: enables debug mode
# - 0 is debug off
# - 1 is debug on
#
# Important: All the properties must be on a single line, and no blank lines!
#
sampling06=3 sampling7=0,2,2,2,2,2,2,0 info=1 palette=0 scanlines=0 mux=0 elk=0 debug=0

Wyświetl plik

@ -1,28 +1,6 @@
# =====================================================================
# config.txt file for RGBtoHDMI (https://github.com/hoglet67/RGBtoHDMI)
# =====================================================================
# =====================================================================
# Default options
# =====================================================================
# No need to change these
# Kernel name
kernel=kernelrpi.img
# Boot quickly
boot_delay=0
# Disable adjusting the refresh rate of RAM every 500 ms
disable_pvt=1
# Don't allow ARM to use Level 2 Cache - this actually speeds up cache misses
disable_l2cache=1
# Enable VSYNC interrupt
fake_vsync_isr=1
# Clock frequency override to make sure we run at 1000MHz
force_turbo=1
arm_freq=1000
@ -32,224 +10,3 @@ kernel_address=0x1f00000
start_file=start_cd.elf
fixup_file=fixup_cd.dat
# =====================================================================
# Common video settings
# =====================================================================
# Use "DVI mode", so the TV's external audio inputs will be activiated
hdmi_drive=1
# Allow framebuffer to have it's aspect ratio warped when scaling
# (needed for mode 7, 504x540 with 4/3 aspect ratio pixels)
framebuffer_aspect=-1
# Ensure default overscan values are 0 (rather than 32/48)
# Without this, the overscan calculation below are more complex and error prone
disable_overscan=1
# =====================================================================
# Monitor configuration
# =====================================================================
# Uncomment the section that matches your monitor resolution
# (and make sure the remaining ones are commented)
## 1920x1080 @ 50Hz
##
## Scale by 1:2 - 672x540 => 1344x1080
## l/r overscan = (1920-1344)/2 = 288
## t/b overscan = (1080-1080)/2 = 0
##
hdmi_group=1
hdmi_mode=31
overscan_left=288
overscan_right=288
overscan_top=0
overscan_bottom=0
## Example using hdmi_timings
##
## hdmi_timings=
## <h_active_pixels>
## <h_sync_polarity
## <h_front_porch>
## <h_sync_pulse>
## <h_back_porch>
## <v_active_lines>
## <v_sync_polarity>
## <v_front_porch>
## <v_sync_pulse>
## <v_back_porch>
## <v_sync_offset_a>
## <v_sync_offset_b>
## <pixel_rep>
## <frame_rate>
## <interlaced>
## <pixel_freq>
## <aspect_ratio>
##
#hdmi_group=2
#hdmi_mode=87
#hdmi_timings=1920 1 528 44 148 1080 1 5 5 35 0 0 0 50 0 148626953 3
#hdmi_timings=1920 1 528 44 148 1080 1 5 5 35 0 0 0 50 0 148000000 3
#overscan_left=288
#overscan_right=288
#overscan_top=0
#overscan_bottom=0
## 1920x1200 @ 50Hz
##
## Scale by 1:2 - 672x540 => 1344x1080
## l/r overscan = (1920-1344)/2 = 288
## t/b overscan = (1200-1080)/2 = 60
##
#hdmi_group=2
#hdmi_mode=87
#hdmi_cvt=1920 1200 50 5 0 0 0
#overscan_left=288
#overscan_right=288
#overscan_top=60
#overscan_bottom=60
## 1600x1200 @ 50Hz
##
## Scale by 1:2 - 672x540 => 1344x1080
## l/r overscan = (1600-1344)/2 = 128
## t/b overscan = (1200-1080)/2 = 60
##
#hdmi_group=2
#hdmi_mode=87
#hdmi_cvt=1600 1200 50 1 0 0 0
#overscan_left=128
#overscan_right=128
#overscan_top=60
#overscan_bottom=60
## 720x576 @ 50Hz
##
## Scale by 1:1 - 672x540 => 672x540
## l/r overscan = (720-672)/2 = 24
## t/b overscan = (576-540)/2 = 18
##
#hdmi_group=1
#hdmi_mode=17
#overscan_left=24
#overscan_right=24
#overscan_top=18
#overscan_bottom=18
## 1280x1024 @ 50Hz
##
## Scale by 1:1.5 - 672x540 => 1008x810
## l/r overscan = (1280-1008)/2 = 136
## t/b overscan = (1024- 810)/2 = 107
##
#hdmi_group=2
#hdmi_mode=87
#hdmi_cvt=1280 1024 50 4 0 0
#overscan_left=136
#overscan_right=136
#overscan_top=107
#overscan_bottom=107
## 1280x720 @ 50Hz
## 1280x800 @ 50Hz
## 1366x768 @ 50Hz
##
## If your native resolution 720p or 768p (i.e. "HD Ready" rather than
## "Full HD") you are not get a very good result:
## - With 1:1 pixel mapping the Beeb image will seem quite small
## - With 1:2 pixel mapping the Beeb image will overflow the screen
## - With something in between there will be nasty scaling artifacts
##
## You are probably best to select 1920x1080 and let the TV do the scaling
##
## Consider the below experimental!
## 1280x720 @ 50Hz
##
## Scale by 1:1.333 - 672x540 => 896x720
## l/r overscan = (1280-896)/2 = 192
## t/b overscan = ( 720-720)/2 = 0
##
#hdmi_group=1
#hdmi_mode=19
#overscan_left=192
#overscan_right=192
#overscan_top=0
#overscan_bottom=0
## 1280x800 @ 50Hz
##
## Scale by 1:1.333 - 672x540 => 896x720
## l/r overscan = (1280-896)/2 = 192
## t/b overscan = ( 800-720)/2 = 40
##
#hdmi_group=2
#hdmi_mode=87
#hdmi_cvt=1280 800 50 5 0 0
#overscan_left=192
#overscan_right=192
#overscan_top=40
#overscan_bottom=40
## 1368x768 @ 50Hz
##
## Scale by 1:1.333 - 672x540 => 896x720
## l/r overscan = (1368-896)/2 = 236
## t/b overscan = ( 768-720)/2 = 24
##
#hdmi_group=2
#hdmi_mode=87
#hdmi_cvt=1368 768 50 3 0 0
#overscan_left=236
#overscan_right=236
#overscan_top=24
#overscan_bottom=24
# Further notes....
#
# Currently the RGBtoHDMI frame buffer sizes are:
# - Mode 0..6 : 672x540 (pixel aspect 1:1)
# - Mode 7 : 504x540 (pixel aspect 4:3)
#
# This is set in defs.h and is slightly larger than the Beeb's
# display to allow a bit of tolerance in where the active area
# is placed (i.e. *TV or games that play with sync position)
#
# For the display to look optimal on HDMI, it's important
# that each Beeb pixel maps exactly 1x1 or 2x2 HDMI pixels.
#
# This is achieved by carefully setting the overscan params.
#
# Start by setting disable_overscan=1. Otherwise the firmware
# mangles the overscan values by adding 32 (SD) or 48 (HD) and
# it all gets very confusing. (HD is 1280 or wider)
#
# It's also important to make sure you monitor doesn't rescale. Look for
# a setting called Just Scan. On my LG 22MN43 this is only available in HD.
#
# Using M0TEST, the difference between the different monitor scaling options
# is very obvious.
#
# Defining custom screen modes is very easy:
#
# hdmi_cvt=<width> <height> <framerate> <aspect> <margins> <interlace> <rb>
#
# Value: Default: Description:
# width (required) width in pixels
# height (required) height in pixels
# framerate (required) framerate in Hz
# aspect 3 aspect ratio 1=4:3, 2=14:9, 3=16:9, 4=5:4, 5=16:10, 6=15:9
# margins 0 0=margins disabled, 1=margins enabled
# interlace 0 0=progressive, 1=interlaced
# rb 0 0=normal, 1=reduced blanking
#
# See https://www.raspberrypi.org/documentation/configuration/config-txt/video.md
#
#
# See also fully annotated config.txt at
# https://raw.githubusercontent.com/Evilpaul/RPi-config/master/config.txt
# (via http://elinux.org/RPiconfig)
#
#

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -38,7 +38,7 @@ RGBtoHDMI
build version: ${NAME}
EOF
cp config.txt cmdline.txt ${DIR}
cp config.txt ${DIR}
cd releases/${NAME}
zip -qr ../${NAME}.zip .
cd ../..