imx8: mainscreen turn on!
supports the lcd panel and adds alot of infrastructure like for the ccm clock module and the i2c controllers.
This commit is contained in:
parent
276f2039a9
commit
931ae0cfeb
13 changed files with 2774 additions and 23 deletions
1357
sys/src/9/imx8/ccm.c
Normal file
1357
sys/src/9/imx8/ccm.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -688,6 +688,16 @@ pnp(Ether *edev)
|
|||
edev->mbps = 1000;
|
||||
edev->maxmtu = Maxtu;
|
||||
|
||||
setclkgate("enet1.ipp_ind_mac0_txclk", 0);
|
||||
setclkgate("sim_enet.mainclk", 0);
|
||||
|
||||
setclkrate("enet1.ipg_clk", "system_pll1_div3", 266*Mhz);
|
||||
setclkrate("enet1.ipp_ind_mac0_txclk", "system_pll2_div8", Moduleclk);
|
||||
setclkrate("enet1.ipg_clk_time", "system_pll2_div10", 25*Mhz);
|
||||
|
||||
setclkgate("enet1.ipp_ind_mac0_txclk", 1);
|
||||
setclkgate("sim_enet.mainclk", 1);
|
||||
|
||||
if(reset(edev) < 0)
|
||||
return -1;
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ extern void meminit(void);
|
|||
extern void putasid(Proc*);
|
||||
|
||||
extern void* ucalloc(usize);
|
||||
extern void* fbmemalloc(usize);
|
||||
|
||||
/* clock */
|
||||
extern void clockinit(void);
|
||||
|
@ -138,3 +139,11 @@ extern void writeconf(void);
|
|||
|
||||
extern int isaconfig(char*, int, ISAConf*);
|
||||
extern void links(void);
|
||||
|
||||
/* ccm */
|
||||
extern void setclkgate(char *name, int on);
|
||||
extern void setclkrate(char *name, char *source, int freq);
|
||||
extern int getclkrate(char *name);
|
||||
|
||||
/* lcd */
|
||||
extern void lcdinit(void);
|
||||
|
|
949
sys/src/9/imx8/lcd.c
Normal file
949
sys/src/9/imx8/lcd.c
Normal file
|
@ -0,0 +1,949 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "io.h"
|
||||
#include "../port/i2c.h"
|
||||
|
||||
#define Image IMAGE
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <cursor.h>
|
||||
#include "screen.h"
|
||||
|
||||
extern Memimage *gscreen;
|
||||
|
||||
/* pinmux registers */
|
||||
enum {
|
||||
IOMUXC_CTL_PAD_SAI5_RXC = 0x144/4, /* for gpio3 20 */
|
||||
IOMUXC_CTL_PAD_SPDIF_RX = 0x1EC/4, /* for pwm2 */
|
||||
IOMUXC_CTL_PAD_GPIO1_IO10 = 0x50/4, /* for gpio1 10 */
|
||||
SION = 1<<4,
|
||||
MUX_MODE = 7,
|
||||
|
||||
IOMUXC_GPR_GPR13 = 0x10034/4, /* GPR13 for MIPI_MUX_SEL */
|
||||
MIPI_MUX_SEL = 1<<2,
|
||||
MIPI_MUX_INV = 1<<3,
|
||||
};
|
||||
|
||||
/* gpio registers */
|
||||
enum {
|
||||
GPIO_DR = 0x00/4,
|
||||
GPIO_GDIR = 0x04/4,
|
||||
GPIO_PSR = 0x08/4,
|
||||
GPIO_ICR1 = 0x0C/4,
|
||||
GPIO_ICR2 = 0x10/4,
|
||||
GPIO_IMR = 0x14/4,
|
||||
GPIO_ISR = 0x18/4,
|
||||
GPIO_EDGE_SEL = 0x1C/4,
|
||||
};
|
||||
|
||||
/* power gating controller registers */
|
||||
enum {
|
||||
GPC_PGC_CPU_0_1_MAPPING = 0xEC/4,
|
||||
GPC_PGC_PU_PGC_SW_PUP_REQ = 0xF8/4,
|
||||
|
||||
GPC_A53_PU_PGC_PUP_STATUS0 = 0x1C4/4,
|
||||
GPC_A53_PU_PGC_PUP_STATUS1 = 0x1C8/4,
|
||||
GPC_A53_PU_PGC_PUP_STATUS2 = 0x1CC/4,
|
||||
DISP_SW_PUP_REQ = 1<<10,
|
||||
HDMI_SW_PUP_REQ = 1<<9,
|
||||
MIPI_SW_PUP_REQ = 1<<0,
|
||||
};
|
||||
|
||||
/* system reset controller registers */
|
||||
enum {
|
||||
SRC_MIPIPHY_RCR = 0x28/4,
|
||||
RCR_MIPI_DSI_PCLK_RESET_N = 1<<5,
|
||||
RCR_MIPI_DSI_ESC_RESET_N = 1<<4,
|
||||
RCR_MIPI_DSI_DPI_RESET_N = 1<<3,
|
||||
RCR_MIPI_DSI_RESET_N = 1<<2,
|
||||
RCR_MIPI_DSI_RESET_BYTE_N = 1<<1,
|
||||
|
||||
SRC_DISP_RCR = 0x34/4,
|
||||
};
|
||||
|
||||
/* pwm controller registers */
|
||||
enum {
|
||||
Pwmsrcclk = 25*Mhz,
|
||||
|
||||
PWMCR = 0x00/4,
|
||||
CR_FWM_1 = 0<<26,
|
||||
CR_FWM_2 = 1<<26,
|
||||
CR_FWM_3 = 2<<26,
|
||||
CR_FWM_4 = 3<<26,
|
||||
|
||||
CR_STOPEN = 1<<25,
|
||||
CR_DOZEN = 1<<24,
|
||||
CR_WAITEN = 1<<23,
|
||||
CR_DBGEN = 1<<22,
|
||||
CR_BCTR = 1<<21,
|
||||
CR_HCTR = 1<<20,
|
||||
|
||||
CR_POUTC = 1<<18,
|
||||
|
||||
CR_CLKSRC_OFF = 0<<16,
|
||||
CR_CLKSRC_IPG = 1<<16,
|
||||
CR_CLKSRC_HIGHFREQ = 2<<16,
|
||||
CR_CLKSRC_32K = 3<<16,
|
||||
|
||||
CR_PRESCALER_SHIFT = 4,
|
||||
|
||||
CR_SWR = 1<<3,
|
||||
|
||||
CR_REPEAT_1 = 0<<1,
|
||||
CR_REPEAT_2 = 1<<1,
|
||||
CR_REPEAT_4 = 2<<1,
|
||||
CR_REPEAT_8 = 3<<1,
|
||||
|
||||
CR_EN = 1<<0,
|
||||
|
||||
PWMSR = 0x04/4,
|
||||
PWMIR = 0x08/4,
|
||||
PWMSAR = 0x0C/4,
|
||||
SAR_MASK = 0xFFFF,
|
||||
PWMPR = 0x10/4,
|
||||
PR_MASK = 0xFFFF,
|
||||
PWMCNR = 0x14/4,
|
||||
CNR_MASK = 0xFFFF,
|
||||
};
|
||||
|
||||
/* dphy registers */
|
||||
enum {
|
||||
DPHY_PD_PHY = 0x0/4,
|
||||
DPHY_M_PRG_HS_PREPARE = 0x4/4,
|
||||
DPHY_MC_PRG_HS_PREPARE = 0x8/4,
|
||||
DPHY_M_PRG_HS_ZERO = 0xc/4,
|
||||
DPHY_MC_PRG_HS_ZERO = 0x10/4,
|
||||
DPHY_M_PRG_HS_TRAIL = 0x14/4,
|
||||
DPHY_MC_PRG_HS_TRAIL = 0x18/4,
|
||||
DPHY_PD_PLL = 0x1c/4,
|
||||
DPHY_TST = 0x20/4,
|
||||
DPHY_CN = 0x24/4,
|
||||
DPHY_CM = 0x28/4,
|
||||
DPHY_CO = 0x2c/4,
|
||||
DPHY_LOCK = 0x30/4,
|
||||
DPHY_LOCK_BYP = 0x34/4,
|
||||
DPHY_RTERM_SEL = 0x38/4,
|
||||
DPHY_AUTO_PD_EN = 0x3c/4,
|
||||
DPHY_RXLPRP = 0x40/4,
|
||||
DPHY_RXCDR = 0x44/4,
|
||||
DPHY_RXHS_SETTLE = 0x48/4, /* undocumented */
|
||||
};
|
||||
|
||||
/* dsi-host registers */
|
||||
enum {
|
||||
DSI_HOST_CFG_NUM_LANES = 0x0/4,
|
||||
DSI_HOST_CFG_NONCONTINUOUS_CLK = 0x4/4,
|
||||
DSI_HOST_CFG_AUTOINSERT_EOTP = 0x14/4,
|
||||
DSI_HOST_CFG_T_PRE = 0x8/4,
|
||||
DSI_HOST_CFG_T_POST = 0xc/4,
|
||||
DSI_HOST_CFG_TX_GAP = 0x10/4,
|
||||
DSI_HOST_CFG_EXTRA_CMDS_AFTER_EOTP = 0x18/4,
|
||||
DSI_HOST_CFG_HTX_TO_COUNT = 0x1c/4,
|
||||
DSI_HOST_CFG_LRX_H_TO_COUNT = 0x20/4,
|
||||
DSI_HOST_CFG_BTA_H_TO_COUNT = 0x24/4,
|
||||
DSI_HOST_CFG_TWAKEUP = 0x28/4,
|
||||
|
||||
DSI_HOST_CFG_DPI_INTERFACE_COLOR_CODING = 0x208/4,
|
||||
DSI_HOST_CFG_DPI_PIXEL_FORMAT = 0x20c/4,
|
||||
DSI_HOST_CFG_DPI_VSYNC_POLARITY = 0x210/4,
|
||||
DSI_HOST_CFG_DPI_HSYNC_POLARITY = 0x214/4,
|
||||
DSI_HOST_CFG_DPI_VIDEO_MODE = 0x218/4,
|
||||
DSI_HOST_CFG_DPI_PIXEL_FIFO_SEND_LEVEL = 0x204/4,
|
||||
DSI_HOST_CFG_DPI_HFP = 0x21c/4,
|
||||
DSI_HOST_CFG_DPI_HBP = 0x220/4,
|
||||
DSI_HOST_CFG_DPI_HSA = 0x224/4,
|
||||
DSI_HOST_CFG_DPI_ENA_BLE_MULT_PKTS = 0x228/4,
|
||||
DSI_HOST_CFG_DPI_BLLP_MODE = 0x234/4,
|
||||
DSI_HOST_CFG_DPI_USE_NULL_PKT_BLLP = 0x238/4,
|
||||
DSI_HOST_CFG_DPI_VC = 0x240/4,
|
||||
DSI_HOST_CFG_DPI_PIXEL_PAYLOAD_SIZE = 0x200/4,
|
||||
DSI_HOST_CFG_DPI_VACTIVE = 0x23c/4,
|
||||
DSI_HOST_CFG_DPI_VBP = 0x22c/4,
|
||||
DSI_HOST_CFG_DPI_VFP = 0x230/4,
|
||||
};
|
||||
|
||||
/* lcdif registers */
|
||||
enum {
|
||||
LCDIF_CTRL = 0x00/4,
|
||||
LCDIF_CTRL_SET = 0x04/4,
|
||||
LCDIF_CTRL_CLR = 0x08/4,
|
||||
LCDIF_CTRL_TOG = 0x0C/4,
|
||||
CTRL_SFTRST = 1<<31,
|
||||
CTRL_CLKGATE = 1<<30,
|
||||
CTRL_YCBCR422_INPUT = 1<<29,
|
||||
CTRL_READ_WEITEB = 1<<28,
|
||||
CTRL_WAIT_FOR_VSYNC_EDGE = 1<<27,
|
||||
CTRL_DATA_SHIFT_DIR = 1<<26,
|
||||
CTRL_SHIFT_NUM_BITS = 0x1F<<21,
|
||||
CTRL_DVI_MODE = 1<<20,
|
||||
CTRL_BYPASS_COUNT = 1<<19,
|
||||
CTRL_VSYNC_MODE = 1<<18,
|
||||
CTRL_DOTCLK_MODE = 1<<17,
|
||||
CTRL_DATA_SELECT = 1<<16,
|
||||
|
||||
CTRL_INPUT_DATA_NO_SWAP = 0<<14,
|
||||
CTRL_INPUT_DATA_LITTLE_ENDIAN = 0<<14,
|
||||
CTRL_INPUT_DATA_BIG_ENDIAB = 1<<14,
|
||||
CTRL_INPUT_DATA_SWAP_ALL_BYTES = 1<<14,
|
||||
CTRL_INPUT_DATA_HWD_SWAP = 2<<14,
|
||||
CTRL_INPUT_DATA_HWD_BYTE_SWAP = 3<<14,
|
||||
|
||||
CTRL_CSC_DATA_NO_SWAP = 0<<12,
|
||||
CTRL_CSC_DATA_LITTLE_ENDIAN = 0<<12,
|
||||
CTRL_CSC_DATA_BIG_ENDIAB = 1<<12,
|
||||
CTRL_CSC_DATA_SWAP_ALL_BYTES = 1<<12,
|
||||
CTRL_CSC_DATA_HWD_SWAP = 2<<12,
|
||||
CTRL_CSC_DATA_HWD_BYTE_SWAP = 3<<12,
|
||||
|
||||
CTRL_LCD_DATABUS_WIDTH_16_BIT = 0<<10,
|
||||
CTRL_LCD_DATABUS_WIDTH_8_BIT = 1<<10,
|
||||
CTRL_LCD_DATABUS_WIDTH_18_BIT = 2<<10,
|
||||
CTRL_LCD_DATABUS_WIDTH_24_BIT = 3<<10,
|
||||
|
||||
CTRL_WORD_LENGTH_16_BIT = 0<<8,
|
||||
CTRL_WORD_LENGTH_8_BIT = 1<<8,
|
||||
CTRL_WORD_LENGTH_18_BIT = 2<<8,
|
||||
CTRL_WORD_LENGTH_24_BIT = 3<<8,
|
||||
|
||||
CTRL_RGB_TO_YCBCR422_CSC = 1<<7,
|
||||
|
||||
CTRL_MASTER = 1<<5,
|
||||
|
||||
CTRL_DATA_FORMAT_16_BIT = 1<<3,
|
||||
CTRL_DATA_FORMAT_18_BIT = 1<<2,
|
||||
CTRL_DATA_FORMAT_24_BIT = 1<<1,
|
||||
|
||||
CTRL_RUN = 1<<0,
|
||||
|
||||
LCDIF_CTRL1 = 0x10/4,
|
||||
LCDIF_CTRL1_SET = 0x14/4,
|
||||
LCDIF_CTRL1_CLR = 0x18/4,
|
||||
LCDIF_CTRL1_TOG = 0x1C/4,
|
||||
CTRL1_COMBINE_MPU_WR_STRB = 1<<27,
|
||||
CTRL1_BM_ERROR_IRQ_EN = 1<<26,
|
||||
CTRL1_BM_ERROR_IRQ = 1<<25,
|
||||
CTRL1_RECOVER_ON_UNDERFLOW = 1<<24,
|
||||
|
||||
CTRL1_INTERLACE_FIELDS = 1<<23,
|
||||
CTRL1_START_INTERLACE_FROM_SECOND_FIELD = 1<<22,
|
||||
|
||||
CTRL1_FIFO_CLEAR = 1<<21,
|
||||
CTRL1_IRQ_ON_ALTERNATE_FIELDS = 1<<20,
|
||||
|
||||
CTRL1_BYTE_PACKING_FORMAT = 0xF<<16,
|
||||
|
||||
CTRL1_OVERFLOW_IRQ_EN = 1<<15,
|
||||
CTRL1_UNDERFLOW_IRQ_EN = 1<<14,
|
||||
CTRL1_CUR_FRAME_DONE_IRQ_EN = 1<<13,
|
||||
CTRL1_VSYNC_EDGE_IRQ_EN = 1<<12,
|
||||
CTRL1_OVERFLOW_IRQ = 1<<11,
|
||||
CTRL1_UNDERFLOW_IRQ = 1<<10,
|
||||
CTRL1_CUR_FRAME_DONE_IRQ = 1<<9,
|
||||
CTRL1_VSYNC_EDGE_IRQ = 1<<8,
|
||||
|
||||
CTRL1_BUSY_ENABLE = 1<<2,
|
||||
CTRL1_MODE86 = 1<<1,
|
||||
CTRL1_RESET = 1<<0,
|
||||
|
||||
LCDIF_CTRL2 = 0x20/4,
|
||||
LCDIF_CTRL2_SET = 0x24/4,
|
||||
LCDIF_CTRL2_CLR = 0x28/4,
|
||||
LCDIF_CTRL2_TOG = 0x2C/4,
|
||||
CTRL2_OUTSTANDING_REQS_REQ_1 = 0<<21,
|
||||
CTRL2_OUTSTANDING_REQS_REQ_2 = 1<<21,
|
||||
CTRL2_OUTSTANDING_REQS_REQ_4 = 2<<21,
|
||||
CTRL2_OUTSTANDING_REQS_REQ_8 = 3<<21,
|
||||
CTRL2_OUTSTANDING_REQS_REQ_16 = 4<<21,
|
||||
|
||||
CTRL2_BURST_LEN_8 = 1<<20,
|
||||
|
||||
CTRL2_ODD_LINE_PATTERN_RGB = 0<<16,
|
||||
CTRL2_ODD_LINE_PATTERN_RBG = 1<<16,
|
||||
CTRL2_ODD_LINE_PATTERN_GBR = 2<<16,
|
||||
CTRL2_ODD_LINE_PATTERN_GRB = 3<<16,
|
||||
CTRL2_ODD_LINE_PATTERN_BRG = 4<<16,
|
||||
CTRL2_ODD_LINE_PATTERN_BGR = 5<<16,
|
||||
|
||||
CTRL2_EVEN_LINE_PATTERN_RGB = 0<<12,
|
||||
CTRL2_EVEN_LINE_PATTERN_RBG = 1<<12,
|
||||
CTRL2_EVEN_LINE_PATTERN_GBR = 2<<12,
|
||||
CTRL2_EVEN_LINE_PATTERN_GRB = 3<<12,
|
||||
CTRL2_EVEN_LINE_PATTERN_BRG = 4<<12,
|
||||
CTRL2_EVEN_LINE_PATTERN_BGR = 5<<12,
|
||||
|
||||
CTRL2_READ_PACK_DIR = 1<<10,
|
||||
|
||||
CTRL2_READ_MODE_OUTPUT_IN_RGB_FORMAT = 1<<9,
|
||||
CTRL2_READ_MODE_6_BIT_INPUT = 1<<8,
|
||||
CTRL2_READ_MODE_NUM_PACKED_SUBWORDS = 7<<4,
|
||||
CTRL2_INITIAL_DUMMY_READS = 7<<1,
|
||||
|
||||
LCDIF_TRANSFER_COUNT= 0x30/4,
|
||||
TRANSFER_COUNT_V_COUNT = 0xFFFF<<16,
|
||||
TRANSFER_COUNT_H_COUNT = 0xFFFF,
|
||||
|
||||
LCDIF_CUR_BUF = 0x40/4,
|
||||
LCDIF_NEXT_BUF = 0x50/4,
|
||||
|
||||
LCDIF_TIMING = 0x60/4,
|
||||
TIMING_CMD_HOLD = 0xFF<<24,
|
||||
TIMING_CMD_SETUP = 0xFF<<16,
|
||||
TIMING_DATA_HOLD = 0xFF<<8,
|
||||
TIMING_DATA_SETUP = 0xFF<<0,
|
||||
|
||||
LCDIF_VDCTRL0 = 0x70/4,
|
||||
VDCTRL0_VSYNC_OEB = 1<<29,
|
||||
VDCTRL0_ENABLE_PRESENT = 1<<28,
|
||||
|
||||
VDCTRL0_VSYNC_POL = 1<<27,
|
||||
VDCTRL0_HSYNC_POL = 1<<26,
|
||||
VDCTRL0_DOTCLK_POL = 1<<25,
|
||||
VDCTRL0_ENABLE_POL = 1<<24,
|
||||
|
||||
VDCTRL0_VSYNC_PERIOD_UNIT = 1<<21,
|
||||
VDCTRL0_VSYNC_PULSE_WIDTH_UNIT = 1<<20,
|
||||
VDCTRL0_HALF_LINE = 1<<19,
|
||||
VDCTRL0_HALF_LINE_MODE = 1<<18,
|
||||
|
||||
VDCTRL0_VSYNC_PULSE_WIDTH = 0x3FFFF,
|
||||
|
||||
LCDIF_VDCTRL1 = 0x80/4,
|
||||
VDCTRL1_VSYNC_PERIOD = 0xFFFFFFFF,
|
||||
|
||||
LCDIF_VDCTRL2 = 0x90/4,
|
||||
VDCTRL2_HSYNC_PERIOD = 0x3FFFF,
|
||||
VDCTRL2_HSYNC_PULSE_WIDTH = 0x3FFF<<18,
|
||||
|
||||
LCDIF_VDCTRL3 = 0xA0/4,
|
||||
VDCTRL3_VERTICAL_WAIT_CNT = 0xFFFF,
|
||||
VDCTRL3_HORIZONTAL_WAIT_CNT = 0xFFF<<16,
|
||||
VDCTRL3_VSYNC_ONLY = 1<<28,
|
||||
VDCTRL3_MUX_SYNC_SIGNALS = 1<<29,
|
||||
|
||||
LCDIF_VDCTRL4 = 0xB0/4,
|
||||
VDCTRL4_DOTCLK_H_VALID_DATA_CNT = 0x3FFFF,
|
||||
VDCTRL4_SYNC_SIGNALS_ON = 1<<18,
|
||||
|
||||
VDCTRL4_DOTCLK_DLY_2NS = 0<<29,
|
||||
VDCTRL4_DOTCLK_DLY_4NS = 1<<29,
|
||||
VDCTRL4_DOTCLK_DLY_6NS = 2<<29,
|
||||
VDCTRL4_DOTCLK_DLY_8NS = 3<<29,
|
||||
|
||||
LCDIF_DATA = 0x180/4,
|
||||
|
||||
LCDIF_STAT = 0x1B0/4,
|
||||
|
||||
LCDIF_AS_CTRL = 0x210/4,
|
||||
};
|
||||
|
||||
struct video_mode {
|
||||
int pixclk;
|
||||
int hactive;
|
||||
int vactive;
|
||||
int hblank;
|
||||
int vblank;
|
||||
int hso;
|
||||
int vso;
|
||||
int hspw;
|
||||
int vspw;
|
||||
|
||||
char vsync_pol;
|
||||
char hsync_pol;
|
||||
};
|
||||
|
||||
struct dsi_cfg {
|
||||
int lanes;
|
||||
|
||||
int ref_clk;
|
||||
int hs_clk;
|
||||
int ui_ps;
|
||||
|
||||
int byte_clk;
|
||||
int byte_t_ps;
|
||||
|
||||
int tx_esc_clk;
|
||||
int tx_esc_t_ps;
|
||||
|
||||
int rx_esc_clk;
|
||||
|
||||
int clk_pre_ps;
|
||||
int clk_prepare_ps;
|
||||
int clk_zero_ps;
|
||||
|
||||
int hs_prepare_ps;
|
||||
int hs_zero_ps;
|
||||
int hs_trail_ps;
|
||||
int hs_exit_ps;
|
||||
|
||||
int lpx_ps;
|
||||
|
||||
vlong wakeup_ps;
|
||||
};
|
||||
|
||||
/* base addresses, VIRTIO is at 0x30000000 physical */
|
||||
|
||||
static u32int *iomuxc = (u32int*)(VIRTIO + 0x330000);
|
||||
|
||||
static u32int *gpio1 = (u32int*)(VIRTIO + 0x200000);
|
||||
static u32int *gpio3 = (u32int*)(VIRTIO + 0x220000);
|
||||
|
||||
static u32int *pwm2 = (u32int*)(VIRTIO + 0x670000);
|
||||
|
||||
static u32int *resetc= (u32int*)(VIRTIO + 0x390000);
|
||||
static u32int *gpc = (u32int*)(VIRTIO + 0x3A0000);
|
||||
|
||||
static u32int *dsi = (u32int*)(VIRTIO + 0xA00000);
|
||||
static u32int *dphy = (u32int*)(VIRTIO + 0xA00300);
|
||||
|
||||
static u32int *lcdif = (u32int*)(VIRTIO + 0x320000);
|
||||
|
||||
/* shift and mask */
|
||||
static u32int
|
||||
sm(u32int v, u32int m)
|
||||
{
|
||||
int s;
|
||||
|
||||
if(m == 0)
|
||||
return 0;
|
||||
|
||||
s = 0;
|
||||
while((m & 1) == 0){
|
||||
m >>= 1;
|
||||
s++;
|
||||
}
|
||||
|
||||
return (v & m) << s;
|
||||
}
|
||||
|
||||
static u32int
|
||||
rr(u32int *base, int reg)
|
||||
{
|
||||
u32int val = base[reg];
|
||||
// iprint("%#p+%#.4x -> %#.8ux\n", PADDR(base), reg*4, val);
|
||||
return val;
|
||||
}
|
||||
static void
|
||||
wr(u32int *base, int reg, u32int val)
|
||||
{
|
||||
// iprint("%#p+%#.4x <- %#.8ux\n", PADDR(base), reg*4, val);
|
||||
base[reg] = val;
|
||||
}
|
||||
static void
|
||||
mr(u32int *base, int reg, u32int val, u32int mask)
|
||||
{
|
||||
wr(base, reg, (rr(base, reg) & ~mask) | (val & mask));
|
||||
}
|
||||
|
||||
static void
|
||||
dsiparams(struct dsi_cfg *cfg, int lanes, int hs_clk, int ref_clk, int tx_esc_clk, int rx_esc_clk)
|
||||
{
|
||||
cfg->lanes = lanes;
|
||||
cfg->ref_clk = ref_clk;
|
||||
|
||||
cfg->hs_clk = hs_clk;
|
||||
cfg->ui_ps = (1000000000000LL + (cfg->hs_clk-1)) / cfg->hs_clk;
|
||||
|
||||
cfg->byte_clk = cfg->hs_clk / 8;
|
||||
cfg->byte_t_ps = cfg->ui_ps * 8;
|
||||
|
||||
cfg->tx_esc_clk = tx_esc_clk;
|
||||
cfg->tx_esc_t_ps = (1000000000000LL + (cfg->tx_esc_clk-1)) / cfg->tx_esc_clk;
|
||||
|
||||
cfg->rx_esc_clk = rx_esc_clk;
|
||||
|
||||
/* min 8*ui */
|
||||
cfg->clk_pre_ps = 8*cfg->ui_ps;
|
||||
|
||||
/* min 38ns, max 95ns */
|
||||
cfg->clk_prepare_ps = 38*1000;
|
||||
|
||||
/* clk_prepare + clk_zero >= 300ns */
|
||||
cfg->clk_zero_ps = 300*1000 - cfg->clk_prepare_ps;
|
||||
|
||||
/* min 40ns + 4*ui, max 85ns + 6*ui */
|
||||
cfg->hs_prepare_ps = 40*1000 + 4*cfg->ui_ps;
|
||||
|
||||
/* hs_prepae + hs_zero >= 145ns + 10*ui */
|
||||
cfg->hs_zero_ps = (145*1000 + 10*cfg->ui_ps) - cfg->hs_prepare_ps;
|
||||
|
||||
/* min max(n*8*ui, 60ns + n*4*ui); n=1 */
|
||||
cfg->hs_trail_ps = 60*1000 + 1*4*cfg->ui_ps;
|
||||
if(cfg->hs_trail_ps < 1*8*cfg->ui_ps)
|
||||
cfg->hs_trail_ps = 1*8*cfg->ui_ps;
|
||||
|
||||
/* min 100ns */
|
||||
cfg->hs_exit_ps = 100*1000;
|
||||
|
||||
/* min 50ns */
|
||||
cfg->lpx_ps = 50*1000;
|
||||
|
||||
/* min 1ms */
|
||||
cfg->wakeup_ps = 1000000000000LL;
|
||||
}
|
||||
|
||||
static void
|
||||
lcdifinit(struct video_mode *mode)
|
||||
{
|
||||
wr(lcdif, LCDIF_CTRL_CLR, CTRL_SFTRST);
|
||||
while(rr(lcdif, LCDIF_CTRL) & CTRL_SFTRST)
|
||||
;
|
||||
wr(lcdif, LCDIF_CTRL_CLR, CTRL_CLKGATE);
|
||||
while(rr(lcdif, LCDIF_CTRL) & (CTRL_SFTRST|CTRL_CLKGATE))
|
||||
;
|
||||
|
||||
wr(lcdif, LCDIF_CTRL1_SET, CTRL1_FIFO_CLEAR);
|
||||
wr(lcdif, LCDIF_AS_CTRL, 0);
|
||||
|
||||
wr(lcdif, LCDIF_CTRL1, sm(7, CTRL1_BYTE_PACKING_FORMAT));
|
||||
|
||||
wr(lcdif, LCDIF_CTRL,
|
||||
CTRL_BYPASS_COUNT |
|
||||
CTRL_MASTER |
|
||||
CTRL_LCD_DATABUS_WIDTH_24_BIT |
|
||||
CTRL_WORD_LENGTH_24_BIT);
|
||||
|
||||
wr(lcdif, LCDIF_TRANSFER_COUNT,
|
||||
sm(mode->vactive, TRANSFER_COUNT_V_COUNT) |
|
||||
sm(mode->hactive, TRANSFER_COUNT_H_COUNT));
|
||||
|
||||
wr(lcdif, LCDIF_VDCTRL0,
|
||||
VDCTRL0_ENABLE_PRESENT |
|
||||
VDCTRL0_VSYNC_POL | VDCTRL0_HSYNC_POL |
|
||||
VDCTRL0_VSYNC_PERIOD_UNIT |
|
||||
VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
|
||||
sm(mode->vspw, VDCTRL0_VSYNC_PULSE_WIDTH));
|
||||
|
||||
wr(lcdif, LCDIF_VDCTRL1,
|
||||
sm(mode->vactive + mode->vblank, VDCTRL1_VSYNC_PERIOD));
|
||||
|
||||
wr(lcdif, LCDIF_VDCTRL2,
|
||||
sm(mode->hactive + mode->hblank, VDCTRL2_HSYNC_PERIOD) |
|
||||
sm(mode->hspw, VDCTRL2_HSYNC_PULSE_WIDTH));
|
||||
|
||||
wr(lcdif, LCDIF_VDCTRL3,
|
||||
sm(mode->vblank - mode->vso, VDCTRL3_VERTICAL_WAIT_CNT) |
|
||||
sm(mode->hblank - mode->hso, VDCTRL3_HORIZONTAL_WAIT_CNT));
|
||||
|
||||
wr(lcdif, LCDIF_VDCTRL4,
|
||||
sm(mode->hactive, VDCTRL4_DOTCLK_H_VALID_DATA_CNT));
|
||||
|
||||
wr(lcdif, LCDIF_CUR_BUF, PADDR(gscreen->data->bdata));
|
||||
wr(lcdif, LCDIF_NEXT_BUF, PADDR(gscreen->data->bdata));
|
||||
|
||||
wr(lcdif, LCDIF_CTRL_SET, CTRL_DOTCLK_MODE);
|
||||
|
||||
mr(lcdif, LCDIF_VDCTRL4, VDCTRL4_SYNC_SIGNALS_ON, VDCTRL4_SYNC_SIGNALS_ON);
|
||||
|
||||
wr(lcdif, LCDIF_CTRL_SET, CTRL_RUN);
|
||||
}
|
||||
|
||||
static void
|
||||
bridgeinit(I2Cdev *dev, struct video_mode *mode, struct dsi_cfg *cfg)
|
||||
{
|
||||
int n;
|
||||
|
||||
// clock derived from dsi clock
|
||||
switch(cfg->hs_clk/2000000){
|
||||
case 384:
|
||||
default: n = 1 << 1; break;
|
||||
case 416: n = 2 << 1; break;
|
||||
case 468: n = 0 << 1; break;
|
||||
case 486: n = 3 << 1; break;
|
||||
case 461: n = 4 << 1; break;
|
||||
}
|
||||
i2cwritebyte(dev, 0x0a, n);
|
||||
|
||||
// single channel A
|
||||
n = 1<<5 | (cfg->lanes-4)<<3 | 3<<1;
|
||||
i2cwritebyte(dev, 0x10, n);
|
||||
|
||||
// Enhanced framing and ASSR
|
||||
i2cwritebyte(dev, 0x5a, 0x05);
|
||||
|
||||
// 2 DP lanes w/o SSC
|
||||
i2cwritebyte(dev, 0x93, 0x20);
|
||||
|
||||
// 2.7Gbps DP data rate
|
||||
i2cwritebyte(dev, 0x94, 0x80);
|
||||
|
||||
// Enable PLL and confirm PLL is locked
|
||||
i2cwritebyte(dev, 0x0d, 0x01);
|
||||
|
||||
// wait for PLL to lock
|
||||
while((i2creadbyte(dev, 0x0a) & 0x80) == 0)
|
||||
;
|
||||
|
||||
// Enable ASSR on display
|
||||
i2cwritebyte(dev, 0x64, 0x01);
|
||||
i2cwritebyte(dev, 0x75, 0x01);
|
||||
i2cwritebyte(dev, 0x76, 0x0a);
|
||||
i2cwritebyte(dev, 0x77, 0x01);
|
||||
i2cwritebyte(dev, 0x78, 0x81);
|
||||
|
||||
// Train link and confirm trained
|
||||
i2cwritebyte(dev, 0x96, 0x0a);
|
||||
while(i2creadbyte(dev, 0x96) != 1)
|
||||
;
|
||||
|
||||
// video timings
|
||||
i2cwritebyte(dev, 0x20, mode->hactive & 0xFF);
|
||||
i2cwritebyte(dev, 0x21, mode->hactive >> 8);
|
||||
i2cwritebyte(dev, 0x24, mode->vactive & 0xFF);
|
||||
i2cwritebyte(dev, 0x25, mode->vactive >> 8);
|
||||
i2cwritebyte(dev, 0x2c, mode->hspw);
|
||||
i2cwritebyte(dev, 0x2d, mode->hspw>>8 | (mode->hsync_pol=='-')<<7);
|
||||
i2cwritebyte(dev, 0x30, mode->vspw);
|
||||
i2cwritebyte(dev, 0x31, mode->vspw>>8 | (mode->vsync_pol=='-')<<7);
|
||||
i2cwritebyte(dev, 0x34, mode->hblank - mode->hspw - mode->hso);
|
||||
i2cwritebyte(dev, 0x36, mode->vblank - mode->vspw - mode->vso);
|
||||
i2cwritebyte(dev, 0x38, mode->hso);
|
||||
i2cwritebyte(dev, 0x3a, mode->vso);
|
||||
|
||||
// Enable video stream, ASSR, enhanced framing
|
||||
i2cwritebyte(dev, 0x5a, 0x0d);
|
||||
}
|
||||
|
||||
static char*
|
||||
parseedid128(struct video_mode *mode, uchar edid[128])
|
||||
{
|
||||
static uchar magic[8] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
|
||||
uchar *p, sum;
|
||||
int i;
|
||||
|
||||
if(memcmp(edid, magic, 8) != 0)
|
||||
return "bad edid magic";
|
||||
|
||||
sum = 0;
|
||||
for(i=0; i<128; i++)
|
||||
sum += edid[i];
|
||||
if(sum != 0)
|
||||
return "bad edid checksum";
|
||||
|
||||
/*
|
||||
* Detailed Timings
|
||||
*/
|
||||
p = edid+8+10+2+5+10+3+16;
|
||||
for(i=0; i<4; i++, p+=18){
|
||||
if((p[0]|p[1])==0)
|
||||
continue;
|
||||
|
||||
memset(mode, 0, sizeof(*mode));
|
||||
|
||||
mode->pixclk = ((p[1]<<8) | p[0]) * 10000;
|
||||
|
||||
mode->hactive = ((p[4] & 0xF0)<<4) | p[2]; /* horizontal active */
|
||||
mode->hblank = ((p[4] & 0x0F)<<8) | p[3]; /* horizontal blanking */
|
||||
mode->vactive = ((p[7] & 0xF0)<<4) | p[5]; /* vertical active */
|
||||
mode->vblank = ((p[7] & 0x0F)<<8) | p[6]; /* vertical blanking */
|
||||
mode->hso = ((p[11] & 0xC0)<<2) | p[8]; /* horizontal sync offset */
|
||||
mode->hspw = ((p[11] & 0x30)<<4) | p[9]; /* horizontal sync pulse width */
|
||||
mode->vso = ((p[11] & 0x0C)<<2) | ((p[10] & 0xF0)>>4); /* vertical sync offset */
|
||||
mode->vspw = ((p[11] & 0x03)<<4) | (p[10] & 0x0F); /* vertical sync pulse width */
|
||||
|
||||
switch((p[17] & 0x18)>>3) {
|
||||
case 3: /* digital separate sync signal; the norm */
|
||||
mode->vsync_pol = (p[17] & 0x04) ? '+' : '-';
|
||||
mode->hsync_pol = (p[17] & 0x02) ? '+' : '-';
|
||||
break;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
return "no edid timings available";
|
||||
}
|
||||
|
||||
static char*
|
||||
getmode(I2Cdev *dev, struct video_mode *mode)
|
||||
{
|
||||
static uchar edid[128];
|
||||
static I2Cdev aux;
|
||||
|
||||
aux.bus = dev->bus;
|
||||
aux.addr = 0x50;
|
||||
aux.subaddr = 1;
|
||||
aux.size = sizeof(edid);
|
||||
|
||||
/* enable passthru mode for address 0x50 (EDID) */
|
||||
i2cwritebyte(dev, 0x60, aux.addr<<1 | 1);
|
||||
addi2cdev(&aux);
|
||||
|
||||
if(i2crecv(&aux, edid, sizeof(edid), 0) != sizeof(edid))
|
||||
return "i2crecv failed to get edid bytes";
|
||||
|
||||
return parseedid128(mode, edid);
|
||||
}
|
||||
|
||||
static void
|
||||
dphyinit(struct dsi_cfg *cfg)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* powerdown */
|
||||
wr(dphy, DPHY_PD_PLL, 1);
|
||||
wr(dphy, DPHY_PD_PHY, 1);
|
||||
|
||||
/* magic */
|
||||
wr(dphy, DPHY_LOCK_BYP, 0);
|
||||
wr(dphy, DPHY_RTERM_SEL, 1);
|
||||
wr(dphy, DPHY_AUTO_PD_EN, 0);
|
||||
wr(dphy, DPHY_RXLPRP, 2);
|
||||
wr(dphy, DPHY_RXCDR, 2);
|
||||
wr(dphy, DPHY_TST, 0x25);
|
||||
|
||||
/* hs timings */
|
||||
n = (2*cfg->hs_prepare_ps - cfg->tx_esc_t_ps) / cfg->tx_esc_t_ps;
|
||||
if(n < 0)
|
||||
n = 0;
|
||||
else if(n > 3)
|
||||
n = 3;
|
||||
wr(dphy, DPHY_M_PRG_HS_PREPARE, n);
|
||||
|
||||
n = (2*cfg->clk_prepare_ps - cfg->tx_esc_t_ps) / cfg->tx_esc_t_ps;
|
||||
if(n < 0)
|
||||
n = 0;
|
||||
else if(n > 1)
|
||||
n = 1;
|
||||
wr(dphy, DPHY_MC_PRG_HS_PREPARE, n);
|
||||
|
||||
n = ((cfg->hs_zero_ps + (cfg->byte_t_ps-1)) / cfg->byte_t_ps) - 6;
|
||||
if(n < 1)
|
||||
n = 1;
|
||||
wr(dphy, DPHY_M_PRG_HS_ZERO, n);
|
||||
|
||||
n = ((cfg->clk_zero_ps + (cfg->byte_t_ps-1)) / cfg->byte_t_ps) - 3;
|
||||
if(n < 1)
|
||||
n = 1;
|
||||
wr(dphy, DPHY_MC_PRG_HS_ZERO, n);
|
||||
|
||||
n = (cfg->hs_trail_ps + (cfg->byte_t_ps-1)) / cfg->byte_t_ps;
|
||||
if(n < 1)
|
||||
n = 1;
|
||||
else if(n > 15)
|
||||
n = 15;
|
||||
wr(dphy, DPHY_M_PRG_HS_TRAIL, n);
|
||||
wr(dphy, DPHY_MC_PRG_HS_TRAIL, n);
|
||||
|
||||
if(cfg->hs_clk < 80*Mhz)
|
||||
n = 0xD;
|
||||
else if(cfg->hs_clk < 90*Mhz)
|
||||
n = 0xC;
|
||||
else if(cfg->hs_clk < 125*Mhz)
|
||||
n = 0xB;
|
||||
else if(cfg->hs_clk < 150*Mhz)
|
||||
n = 0xA;
|
||||
else if(cfg->hs_clk < 225*Mhz)
|
||||
n = 0x9;
|
||||
else if(cfg->hs_clk < 500*Mhz)
|
||||
n = 0x8;
|
||||
else
|
||||
n = 0x7;
|
||||
wr(dphy, DPHY_RXHS_SETTLE, n);
|
||||
|
||||
/* hs_clk = ref_clk * (CM / (CN*CO)); just set CN=CO=1 */
|
||||
n = (cfg->hs_clk + cfg->ref_clk-1) / cfg->ref_clk;
|
||||
|
||||
/* strange encoding for CM */
|
||||
if(n < 32)
|
||||
n = 0xE0 | (n - 16);
|
||||
else if(n < 64)
|
||||
n = 0xC0 | (n - 32);
|
||||
else if(n < 128)
|
||||
n = 0x80 | (n - 64);
|
||||
else
|
||||
n = n - 128;
|
||||
wr(dphy, DPHY_CM, n);
|
||||
|
||||
wr(dphy, DPHY_CN, 0x1F); /* CN==1 */
|
||||
wr(dphy, DPHY_CO, 0x00); /* CO==1 */
|
||||
}
|
||||
|
||||
static void
|
||||
dphypowerup(void)
|
||||
{
|
||||
wr(dphy, DPHY_PD_PLL, 0);
|
||||
while((rr(dphy, DPHY_LOCK) & 1) == 0)
|
||||
;
|
||||
wr(dphy, DPHY_PD_PHY, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
dsiinit(struct dsi_cfg *cfg)
|
||||
{
|
||||
int n;
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_NUM_LANES, cfg->lanes-1);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_NONCONTINUOUS_CLK, 0x0);
|
||||
wr(dsi, DSI_HOST_CFG_AUTOINSERT_EOTP, 0x0);
|
||||
|
||||
n = (cfg->clk_pre_ps + cfg->byte_t_ps-1) / cfg->byte_t_ps;
|
||||
wr(dsi, DSI_HOST_CFG_T_PRE, n);
|
||||
|
||||
n = (cfg->clk_pre_ps + cfg->lpx_ps + cfg->clk_prepare_ps + cfg->clk_zero_ps + cfg->byte_t_ps-1) / cfg->byte_t_ps;
|
||||
wr(dsi, DSI_HOST_CFG_T_POST, n);
|
||||
|
||||
n = (cfg->hs_exit_ps + cfg->byte_t_ps-1) / cfg->byte_t_ps;
|
||||
wr(dsi, DSI_HOST_CFG_TX_GAP, n);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_EXTRA_CMDS_AFTER_EOTP, 0x1);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_HTX_TO_COUNT, 0x0);
|
||||
wr(dsi, DSI_HOST_CFG_LRX_H_TO_COUNT, 0x0);
|
||||
wr(dsi, DSI_HOST_CFG_BTA_H_TO_COUNT, 0x0);
|
||||
|
||||
n = (cfg->wakeup_ps + cfg->tx_esc_t_ps-1) / cfg->tx_esc_t_ps;
|
||||
wr(dsi, DSI_HOST_CFG_TWAKEUP, n);
|
||||
}
|
||||
|
||||
static void
|
||||
dpiinit(struct video_mode *mode)
|
||||
{
|
||||
wr(dsi, DSI_HOST_CFG_DPI_INTERFACE_COLOR_CODING, 0x5); // 24-bit
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_PIXEL_FORMAT, 0x3); // 24-bit
|
||||
|
||||
/* this seems wrong */
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VSYNC_POLARITY, 0);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_HSYNC_POLARITY, 0);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VIDEO_MODE, 0x1); // non-burst mode with sync events
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_PIXEL_FIFO_SEND_LEVEL, mode->hactive);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_HFP, mode->hso);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_HBP, mode->hblank - mode->hspw - mode->hso);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_HSA, mode->hspw);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_ENA_BLE_MULT_PKTS, 0x0);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_BLLP_MODE, 0x1);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_USE_NULL_PKT_BLLP, 0x0);
|
||||
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VC, 0x0);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_PIXEL_PAYLOAD_SIZE, mode->hactive);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VACTIVE, mode->vactive - 1);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VBP, mode->vblank - mode->vspw - mode->vso);
|
||||
wr(dsi, DSI_HOST_CFG_DPI_VFP, mode->vso);
|
||||
}
|
||||
|
||||
void
|
||||
lcdinit(void)
|
||||
{
|
||||
struct dsi_cfg dsi_cfg;
|
||||
struct video_mode mode;
|
||||
I2Cdev *bridge;
|
||||
char *err;
|
||||
|
||||
/* gpio3 20 for sn65dsi86 bridge */
|
||||
mr(iomuxc, IOMUXC_CTL_PAD_SAI5_RXC, 5, MUX_MODE);
|
||||
/* gpio1 10 pad for panel */
|
||||
mr(iomuxc, IOMUXC_CTL_PAD_GPIO1_IO10, 0, MUX_MODE);
|
||||
/* pwm2 pad */
|
||||
mr(iomuxc, IOMUXC_CTL_PAD_SPDIF_RX, 1, MUX_MODE);
|
||||
|
||||
/* lcdif to dpi=0, dcss=1 */
|
||||
mr(iomuxc, IOMUXC_GPR_GPR13, 0, MIPI_MUX_SEL);
|
||||
|
||||
setclkgate("gpio1.ipg_clk_s", 1);
|
||||
setclkgate("gpio3.ipg_clk_s", 1);
|
||||
|
||||
setclkrate("pwm2.ipg_clk_high_freq", "osc_25m_ref_clk", Pwmsrcclk);
|
||||
setclkgate("pwm2.ipg_clk_high_freq", 1);
|
||||
|
||||
mr(gpio1, GPIO_GDIR, 1<<10, 1<<10); /* gpio1 10 output */
|
||||
mr(gpio1, GPIO_DR, 0<<10, 1<<10); /* gpio1 10 low: panel off */
|
||||
|
||||
wr(pwm2, PWMIR, 0);
|
||||
wr(pwm2, PWMCR, CR_STOPEN | CR_DOZEN | CR_WAITEN | CR_DBGEN | CR_CLKSRC_HIGHFREQ | 0<<CR_PRESCALER_SHIFT);
|
||||
wr(pwm2, PWMSAR, Pwmsrcclk/150000);
|
||||
wr(pwm2, PWMPR, (Pwmsrcclk/100000)-2);
|
||||
mr(pwm2, PWMCR, CR_EN, CR_EN);
|
||||
|
||||
mr(gpio1, GPIO_DR, 1<<10, 1<<10); /* gpio1 10 high: panel on */
|
||||
|
||||
mr(gpio3, GPIO_GDIR, 1<<20, 1<<20); /* gpio3 20 output */
|
||||
mr(gpio3, GPIO_DR, 1<<20, 1<<20); /* gpio3 20 high: bridge on */
|
||||
|
||||
bridge = i2cdev(i2cbus("i2c4"), 0x2C);
|
||||
if(bridge == nil)
|
||||
return;
|
||||
bridge->subaddr = 1;
|
||||
|
||||
/* power on mipi dsi */
|
||||
wr(gpc, GPC_PGC_CPU_0_1_MAPPING, 0x0000FFFF);
|
||||
mr(gpc, GPC_PGC_PU_PGC_SW_PUP_REQ, MIPI_SW_PUP_REQ, MIPI_SW_PUP_REQ);
|
||||
while(rr(gpc, GPC_PGC_PU_PGC_SW_PUP_REQ) & MIPI_SW_PUP_REQ)
|
||||
;
|
||||
wr(gpc, GPC_PGC_CPU_0_1_MAPPING, 0);
|
||||
|
||||
mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_RESET_N);
|
||||
mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_PCLK_RESET_N);
|
||||
mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_ESC_RESET_N);
|
||||
mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_RESET_BYTE_N);
|
||||
mr(resetc, SRC_MIPIPHY_RCR, 0, RCR_MIPI_DSI_DPI_RESET_N);
|
||||
|
||||
setclkgate("sim_display.mainclk", 0);
|
||||
setclkgate("disp.axi_clk", 0);
|
||||
setclkrate("disp.axi_clk", "system_pll1_clk", 800*Mhz);
|
||||
setclkrate("disp.rtrm_clk", "system_pll1_clk", 400*Mhz);
|
||||
setclkgate("disp.axi_clk", 1);
|
||||
setclkgate("sim_display.mainclk", 1);
|
||||
|
||||
setclkrate("mipi.core", "system_pll1_div3", 266*Mhz);
|
||||
setclkrate("mipi.CLKREF", "system_pll2_clk", 25*Mhz);
|
||||
setclkrate("mipi.RxClkEsc", "system_pll1_clk", 80*Mhz);
|
||||
setclkrate("mipi.TxClkEsc", nil, 20*Mhz);
|
||||
|
||||
/* dsi parameters are fixed for the bridge */
|
||||
dsiparams(&dsi_cfg, 4, 2*486*Mhz,
|
||||
getclkrate("mipi.CLKREF"),
|
||||
getclkrate("mipi.TxClkEsc"),
|
||||
getclkrate("mipi.RxClkEsc"));
|
||||
|
||||
/* release dphy reset */
|
||||
mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_PCLK_RESET_N, RCR_MIPI_DSI_PCLK_RESET_N);
|
||||
|
||||
dphyinit(&dsi_cfg);
|
||||
dsiinit(&dsi_cfg);
|
||||
dphypowerup();
|
||||
|
||||
/* release mipi clock resets (generated by the dphy) */
|
||||
mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_ESC_RESET_N, RCR_MIPI_DSI_ESC_RESET_N);
|
||||
mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_RESET_BYTE_N, RCR_MIPI_DSI_RESET_BYTE_N);
|
||||
|
||||
/*
|
||||
* get mode information from EDID, this can only be done after the clocks
|
||||
* are generated by the DPHY and the clock resets have been released.
|
||||
*/
|
||||
err = getmode(bridge, &mode);
|
||||
if(err != nil)
|
||||
goto out;
|
||||
|
||||
/* allocates the framebuffer (gscreen->data->bdata) */
|
||||
if(screeninit(mode.hactive, mode.vactive, 32) < 0){
|
||||
err = "screeninit failed";
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* start the pixel clock */
|
||||
setclkrate("lcdif.pix_clk", "system_pll1_clk", mode.pixclk);
|
||||
dpiinit(&mode);
|
||||
|
||||
/* release dpi reset */
|
||||
mr(resetc, SRC_MIPIPHY_RCR, RCR_MIPI_DSI_DPI_RESET_N, RCR_MIPI_DSI_DPI_RESET_N);
|
||||
|
||||
/* enable display port bridge */
|
||||
bridgeinit(bridge, &mode, &dsi_cfg);
|
||||
|
||||
/* send the pixels */
|
||||
lcdifinit(&mode);
|
||||
return;
|
||||
|
||||
out:
|
||||
print("lcdinit: %s\n", err);
|
||||
}
|
|
@ -32,6 +32,7 @@ init0(void)
|
|||
poperror();
|
||||
}
|
||||
kproc("alarm", alarmkproc, 0);
|
||||
|
||||
sp = (char**)(USTKTOP-sizeof(Tos) - 8 - sizeof(sp[0])*4);
|
||||
sp[3] = sp[2] = sp[1] = nil;
|
||||
strcpy(sp[1] = (char*)&sp[4], "boot");
|
||||
|
@ -99,14 +100,7 @@ confinit(void)
|
|||
+ conf.nswap
|
||||
+ conf.nswppo*sizeof(Page*);
|
||||
mainmem->maxsize = kpages;
|
||||
if(!cpuserver)
|
||||
/*
|
||||
* give terminals lots of image memory, too; the dynamic
|
||||
* allocation will balance the load properly, hopefully.
|
||||
* be careful with 32-bit overflow.
|
||||
*/
|
||||
imagmem->maxsize = kpages;
|
||||
|
||||
imagmem->maxsize = kpages;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -149,7 +143,6 @@ main(void)
|
|||
fpuinit();
|
||||
intrinit();
|
||||
clockinit();
|
||||
print("cpu%d: UP!\n", m->machno);
|
||||
synccycles();
|
||||
timersinit();
|
||||
flushtlb();
|
||||
|
@ -175,6 +168,7 @@ main(void)
|
|||
initseg();
|
||||
links();
|
||||
chandevreset();
|
||||
lcdinit();
|
||||
userinit();
|
||||
mpinit();
|
||||
mmu0clear((uintptr*)L1);
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
#define STACKALIGN(sp) ((sp) & ~7) /* bug: assure with alloc */
|
||||
#define TRAPFRAMESIZE (38*8)
|
||||
|
||||
/* reserved dram for ucalloc() at the end of KZERO (physical) */
|
||||
/* reserved dram for ucalloc() and fbmemalloc() at the end of KZERO (physical) */
|
||||
#define UCRAMBASE (-KZERO - UCRAMSIZE)
|
||||
#define UCRAMSIZE (1*MiB)
|
||||
#define UCRAMSIZE (8*MiB)
|
||||
|
||||
#define VDRAM (0xFFFFFFFFC0000000ULL) /* 0x40000000 - 0x80000000 */
|
||||
#define KTZERO (VDRAM + 0x100000) /* kernel text start */
|
||||
|
@ -54,7 +54,7 @@
|
|||
#define VMAP (0xFFFFFFFF00000000ULL) /* 0x00000000 - 0x40000000 */
|
||||
|
||||
#define KMAPEND (0xFFFFFFFF00000000ULL) /* 0x140000000 */
|
||||
#define KMAP (0xFFFFFFFE00000000ULL) /* 0x40000000 */
|
||||
#define KMAP (0xFFFFFFFE00000000ULL) /* 0x40000000 */
|
||||
|
||||
#define KSEG0 (0xFFFFFFFE00000000ULL)
|
||||
|
||||
|
|
|
@ -58,12 +58,12 @@ OBJ=\
|
|||
# HFILES=
|
||||
|
||||
LIB=\
|
||||
# /$objtype/lib/libmemlayer.a\
|
||||
# /$objtype/lib/libmemdraw.a\
|
||||
# /$objtype/lib/libdraw.a\
|
||||
/$objtype/lib/libmemlayer.a\
|
||||
/$objtype/lib/libmemdraw.a\
|
||||
/$objtype/lib/libdraw.a\
|
||||
/$objtype/lib/libip.a\
|
||||
/$objtype/lib/libsec.a\
|
||||
# /$objtype/lib/libmp.a\
|
||||
/$objtype/lib/libmp.a\
|
||||
/$objtype/lib/libc.a\
|
||||
# /$objtype/lib/libdtracy.a\
|
||||
|
||||
|
|
|
@ -472,21 +472,36 @@ checkmmu(uintptr, uintptr)
|
|||
{
|
||||
}
|
||||
|
||||
void*
|
||||
ucalloc(usize size)
|
||||
static void*
|
||||
ucramalloc(usize size, uintptr align, uint attr)
|
||||
{
|
||||
static uintptr top = UCRAMBASE + UCRAMSIZE;
|
||||
static Lock lk;
|
||||
uintptr va;
|
||||
|
||||
size = PGROUND(size);
|
||||
uintptr va, pg;
|
||||
|
||||
lock(&lk);
|
||||
top -= size;
|
||||
size += top & align-1;
|
||||
top &= -align;
|
||||
if(top < UCRAMBASE)
|
||||
panic("ucalloc: %p needs %zd bytes\n", getcallerpc(&size), size);
|
||||
panic("ucramalloc: need %zd bytes", size);
|
||||
va = KZERO + top;
|
||||
pg = va & -BY2PG;
|
||||
if(pg != ((va+size) & -BY2PG))
|
||||
mmukmap(pg | attr, pg - KZERO, PGROUND(size));
|
||||
unlock(&lk);
|
||||
|
||||
return (void*)mmukmap(va | PTEUNCACHED, PADDR(va), size);
|
||||
return (void*)va;
|
||||
}
|
||||
|
||||
void*
|
||||
ucalloc(usize size)
|
||||
{
|
||||
return ucramalloc(size, 8, PTEUNCACHED);
|
||||
}
|
||||
|
||||
void*
|
||||
fbmemalloc(usize size)
|
||||
{
|
||||
return ucramalloc(PGROUND(size), BY2PG, PTEWT);
|
||||
}
|
||||
|
|
|
@ -14,14 +14,18 @@ dev
|
|||
fs
|
||||
ether netif
|
||||
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
|
||||
draw screen swcursor
|
||||
mouse screen swcursor
|
||||
uart
|
||||
usb
|
||||
i2c
|
||||
|
||||
link
|
||||
usbxhciimx
|
||||
etherimx ethermii
|
||||
ethermedium
|
||||
loopbackmedium
|
||||
i2cimx devi2c
|
||||
ip
|
||||
tcp
|
||||
udp
|
||||
|
@ -31,8 +35,10 @@ ip
|
|||
icmp6
|
||||
ipmux
|
||||
misc
|
||||
ccm
|
||||
gic
|
||||
uartimx
|
||||
lcd
|
||||
port
|
||||
int cpuserver = 0;
|
||||
bootdir
|
||||
|
|
341
sys/src/9/imx8/screen.c
Normal file
341
sys/src/9/imx8/screen.c
Normal file
|
@ -0,0 +1,341 @@
|
|||
#include "u.h"
|
||||
#include "../port/lib.h"
|
||||
#include "mem.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
#define Image IMAGE
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <cursor.h>
|
||||
#include "screen.h"
|
||||
|
||||
enum {
|
||||
Tabstop = 4,
|
||||
Scroll = 8,
|
||||
};
|
||||
|
||||
Memimage *gscreen;
|
||||
|
||||
static Memdata xgdata;
|
||||
static Memimage xgscreen;
|
||||
static Memimage *conscol;
|
||||
static Memimage *back;
|
||||
static Memsubfont *memdefont;
|
||||
|
||||
static Lock screenlock;
|
||||
|
||||
static Point curpos;
|
||||
static int h, w;
|
||||
static Rectangle window;
|
||||
|
||||
static void myscreenputs(char *s, int n);
|
||||
static void screenputc(char *buf);
|
||||
static void screenwin(void);
|
||||
|
||||
enum
|
||||
{
|
||||
CMaccelerated,
|
||||
CMlinear,
|
||||
};
|
||||
|
||||
static Cmdtab mousectlmsg[] =
|
||||
{
|
||||
CMaccelerated, "accelerated", 0,
|
||||
CMlinear, "linear", 1,
|
||||
};
|
||||
|
||||
void
|
||||
mousectl(Cmdbuf *cb)
|
||||
{
|
||||
Cmdtab *ct;
|
||||
|
||||
ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
|
||||
switch(ct->index){
|
||||
case CMaccelerated:
|
||||
mouseaccelerate(cb->nf == 1? 1: atoi(cb->f[1]));
|
||||
break;
|
||||
case CMlinear:
|
||||
mouseaccelerate(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cursoron(void)
|
||||
{
|
||||
swcursorhide(0);
|
||||
swcursordraw(mousexy());
|
||||
}
|
||||
|
||||
void
|
||||
cursoroff(void)
|
||||
{
|
||||
swcursorhide(0);
|
||||
}
|
||||
|
||||
void
|
||||
setcursor(Cursor* curs)
|
||||
{
|
||||
swcursorload(curs);
|
||||
}
|
||||
|
||||
int
|
||||
hwdraw(Memdrawparam *par)
|
||||
{
|
||||
Memimage *dst, *src, *mask;
|
||||
|
||||
if((dst = par->dst) == nil || dst->data == nil)
|
||||
return 0;
|
||||
if((src = par->src) && src->data == nil)
|
||||
src = nil;
|
||||
if((mask = par->mask) && mask->data == nil)
|
||||
mask = nil;
|
||||
|
||||
if(dst->data->bdata == xgdata.bdata)
|
||||
swcursoravoid(par->r);
|
||||
if(src && src->data->bdata == xgdata.bdata)
|
||||
swcursoravoid(par->sr);
|
||||
if(mask && mask->data->bdata == xgdata.bdata)
|
||||
swcursoravoid(par->mr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
screeninit(int width, int height, int depth)
|
||||
{
|
||||
ulong chan;
|
||||
|
||||
switch(depth){
|
||||
default:
|
||||
return -1;
|
||||
case 32:
|
||||
chan = XRGB32;
|
||||
break;
|
||||
case 24:
|
||||
chan = RGB24;
|
||||
break;
|
||||
case 16:
|
||||
chan = RGB16;
|
||||
break;
|
||||
}
|
||||
memsetchan(&xgscreen, chan);
|
||||
xgscreen.r = Rect(0, 0, width, height);
|
||||
xgscreen.clipr = xgscreen.r;
|
||||
xgscreen.depth = depth;
|
||||
xgscreen.width = wordsperline(xgscreen.r, xgscreen.depth);
|
||||
xgdata.bdata = fbmemalloc(xgscreen.width*sizeof(ulong)*height);
|
||||
xgdata.ref = 1;
|
||||
|
||||
xgscreen.data = &xgdata;
|
||||
|
||||
gscreen = &xgscreen;
|
||||
|
||||
conf.monitor = 1;
|
||||
|
||||
memimageinit();
|
||||
memdefont = getmemdefont();
|
||||
screenwin();
|
||||
myscreenputs(kmesg.buf, kmesg.n);
|
||||
screenputs = myscreenputs;
|
||||
swcursorinit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
flushmemscreen(Rectangle)
|
||||
{
|
||||
}
|
||||
|
||||
Memdata*
|
||||
attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
|
||||
{
|
||||
if(gscreen == nil)
|
||||
return nil;
|
||||
|
||||
*r = gscreen->r;
|
||||
*d = gscreen->depth;
|
||||
*chan = gscreen->chan;
|
||||
*width = gscreen->width;
|
||||
*softscreen = 0;
|
||||
|
||||
gscreen->data->ref++;
|
||||
return gscreen->data;
|
||||
}
|
||||
|
||||
void
|
||||
getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
|
||||
{
|
||||
USED(p, pr, pg, pb);
|
||||
}
|
||||
|
||||
int
|
||||
setcolor(ulong p, ulong r, ulong g, ulong b)
|
||||
{
|
||||
USED(p, r, g, b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
blankscreen(int)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
myscreenputs(char *s, int n)
|
||||
{
|
||||
int i;
|
||||
Rune r;
|
||||
char buf[4];
|
||||
|
||||
if(!islo()) {
|
||||
/* don't deadlock trying to print in interrupt */
|
||||
if(!canlock(&screenlock))
|
||||
return;
|
||||
}
|
||||
else
|
||||
lock(&screenlock);
|
||||
|
||||
while(n > 0){
|
||||
i = chartorune(&r, s);
|
||||
if(i == 0){
|
||||
s++;
|
||||
--n;
|
||||
continue;
|
||||
}
|
||||
memmove(buf, s, i);
|
||||
buf[i] = 0;
|
||||
n -= i;
|
||||
s += i;
|
||||
screenputc(buf);
|
||||
}
|
||||
unlock(&screenlock);
|
||||
}
|
||||
|
||||
static void
|
||||
screenwin(void)
|
||||
{
|
||||
char *greet;
|
||||
Memimage *orange;
|
||||
Point p, q;
|
||||
Rectangle r;
|
||||
|
||||
back = memblack;
|
||||
conscol = memwhite;
|
||||
|
||||
orange = allocmemimage(Rect(0, 0, 1, 1), RGB16);
|
||||
orange->flags |= Frepl;
|
||||
orange->clipr = gscreen->r;
|
||||
orange->data->bdata[0] = 0x40; /* magic: colour? */
|
||||
orange->data->bdata[1] = 0xfd; /* magic: colour? */
|
||||
|
||||
w = memdefont->info[' '].width;
|
||||
h = memdefont->height;
|
||||
|
||||
r = gscreen->r;
|
||||
memimagedraw(gscreen, r, memwhite, ZP, memopaque, ZP, S);
|
||||
window = insetrect(r, 4);
|
||||
memimagedraw(gscreen, window, memblack, ZP, memopaque, ZP, S);
|
||||
|
||||
memimagedraw(gscreen, Rect(window.min.x, window.min.y,
|
||||
window.max.x, window.min.y + h + 5 + 6), orange, ZP, nil, ZP, S);
|
||||
|
||||
freememimage(orange);
|
||||
window = insetrect(window, 5);
|
||||
|
||||
greet = " Plan 9 Console ";
|
||||
p = addpt(window.min, Pt(10, 0));
|
||||
q = memsubfontwidth(memdefont, greet);
|
||||
memimagestring(gscreen, p, conscol, ZP, memdefont, greet);
|
||||
flushmemscreen(r);
|
||||
window.min.y += h + 6;
|
||||
curpos = window.min;
|
||||
window.max.y = window.min.y + ((window.max.y - window.min.y) / h) * h;
|
||||
}
|
||||
|
||||
static void
|
||||
scroll(void)
|
||||
{
|
||||
int o;
|
||||
Point p;
|
||||
Rectangle r;
|
||||
|
||||
o = Scroll*h;
|
||||
r = Rpt(window.min, Pt(window.max.x, window.max.y-o));
|
||||
p = Pt(window.min.x, window.min.y+o);
|
||||
memimagedraw(gscreen, r, gscreen, p, nil, p, S);
|
||||
flushmemscreen(r);
|
||||
r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
|
||||
memimagedraw(gscreen, r, back, ZP, nil, ZP, S);
|
||||
flushmemscreen(r);
|
||||
|
||||
curpos.y -= o;
|
||||
}
|
||||
|
||||
static void
|
||||
screenputc(char *buf)
|
||||
{
|
||||
int w;
|
||||
uint pos;
|
||||
Point p;
|
||||
Rectangle r;
|
||||
static int *xp;
|
||||
static int xbuf[256];
|
||||
|
||||
if (xp < xbuf || xp >= &xbuf[nelem(xbuf)])
|
||||
xp = xbuf;
|
||||
|
||||
switch (buf[0]) {
|
||||
case '\n':
|
||||
if (curpos.y + h >= window.max.y)
|
||||
scroll();
|
||||
curpos.y += h;
|
||||
screenputc("\r");
|
||||
break;
|
||||
case '\r':
|
||||
xp = xbuf;
|
||||
curpos.x = window.min.x;
|
||||
break;
|
||||
case '\t':
|
||||
p = memsubfontwidth(memdefont, " ");
|
||||
w = p.x;
|
||||
if (curpos.x >= window.max.x - Tabstop * w)
|
||||
screenputc("\n");
|
||||
|
||||
pos = (curpos.x - window.min.x) / w;
|
||||
pos = Tabstop - pos % Tabstop;
|
||||
*xp++ = curpos.x;
|
||||
r = Rect(curpos.x, curpos.y, curpos.x + pos * w, curpos.y + h);
|
||||
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
|
||||
flushmemscreen(r);
|
||||
curpos.x += pos * w;
|
||||
break;
|
||||
case '\b':
|
||||
if (xp <= xbuf)
|
||||
break;
|
||||
xp--;
|
||||
r = Rect(*xp, curpos.y, curpos.x, curpos.y + h);
|
||||
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
|
||||
flushmemscreen(r);
|
||||
curpos.x = *xp;
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
default:
|
||||
p = memsubfontwidth(memdefont, buf);
|
||||
w = p.x;
|
||||
|
||||
if (curpos.x >= window.max.x - w)
|
||||
screenputc("\n");
|
||||
|
||||
*xp++ = curpos.x;
|
||||
r = Rect(curpos.x, curpos.y, curpos.x + w, curpos.y + h);
|
||||
memimagedraw(gscreen, r, back, back->r.min, nil, back->r.min, S);
|
||||
memimagestring(gscreen, curpos, conscol, ZP, memdefont, buf);
|
||||
flushmemscreen(r);
|
||||
curpos.x += w;
|
||||
break;
|
||||
}
|
||||
}
|
32
sys/src/9/imx8/screen.h
Normal file
32
sys/src/9/imx8/screen.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* devmouse.c */
|
||||
typedef struct Cursor Cursor;
|
||||
extern Cursor cursor;
|
||||
extern void mousetrack(int, int, int, ulong);
|
||||
extern void absmousetrack(int, int, int, ulong);
|
||||
extern Point mousexy(void);
|
||||
extern void mouseaccelerate(int);
|
||||
|
||||
/* screen.c */
|
||||
extern int screeninit(int width, int hight, int depth);
|
||||
extern void blankscreen(int);
|
||||
extern void flushmemscreen(Rectangle);
|
||||
extern Memdata* attachscreen(Rectangle*, ulong*, int*, int*, int*);
|
||||
extern void cursoron(void);
|
||||
extern void cursoroff(void);
|
||||
extern void setcursor(Cursor*);
|
||||
|
||||
extern void mousectl(Cmdbuf*);
|
||||
extern void mouseresize(void);
|
||||
extern void mouseredraw(void);
|
||||
|
||||
/* devdraw.c */
|
||||
extern QLock drawlock;
|
||||
|
||||
#define ishwimage(i) 1 /* for ../port/devdraw.c */
|
||||
|
||||
/* swcursor.c */
|
||||
void swcursorhide(int);
|
||||
void swcursoravoid(Rectangle);
|
||||
void swcursordraw(Point);
|
||||
void swcursorload(Cursor *);
|
||||
void swcursorinit(void);
|
|
@ -314,18 +314,36 @@ interrupt(Ureg*, void *arg)
|
|||
uartkick(uart);
|
||||
}
|
||||
|
||||
static void
|
||||
clkenable(Uart *u, int on)
|
||||
{
|
||||
char clk[32];
|
||||
|
||||
snprint(clk, sizeof(clk), "%s.ipg_perclk", u->name);
|
||||
if(on) setclkrate(clk, "osc_25m_ref_clk", u->freq);
|
||||
setclkgate(clk, on);
|
||||
}
|
||||
|
||||
static void
|
||||
disable(Uart *u)
|
||||
{
|
||||
u32int *regs = u->regs;
|
||||
|
||||
if(u->console)
|
||||
return; /* avoid glitch */
|
||||
|
||||
regs[UCR1] = 0;
|
||||
clkenable(u, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
enable(Uart *u, int ie)
|
||||
{
|
||||
disable(u);
|
||||
clkenable(u, 1);
|
||||
|
||||
if(ie) intrenable(IRQuart1, interrupt, u, BUSUNKNOWN, u->name);
|
||||
|
||||
config(u);
|
||||
}
|
||||
|
||||
|
|
|
@ -1774,6 +1774,17 @@ portreset(Hci *hp, int port, int on)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
clkenable(int i, int on)
|
||||
{
|
||||
char clk[32];
|
||||
|
||||
snprint(clk, sizeof(clk), "usb%d.ctrl", i+1);
|
||||
setclkgate(clk, on);
|
||||
snprint(clk, sizeof(clk), "usb%d.phy", i+1);
|
||||
setclkgate(clk, on);
|
||||
}
|
||||
|
||||
static int
|
||||
reset(Hci *hp)
|
||||
{
|
||||
|
@ -1796,6 +1807,15 @@ reset(Hci *hp)
|
|||
return -1;
|
||||
|
||||
Found:
|
||||
if(i == 0){
|
||||
for(i = 0; i < nelem(ctlrs); i++) clkenable(i, 0);
|
||||
setclkrate("ccm_usb_bus_clk_root", "system_pll2_div2", 500*Mhz);
|
||||
setclkrate("ccm_usb_core_ref_clk_root", "system_pll1_div8", 100*Mhz);
|
||||
setclkrate("ccm_usb_phy_ref_clk_root", "system_pll1_div8", 100*Mhz);
|
||||
i = 0;
|
||||
}
|
||||
clkenable(i, 1);
|
||||
|
||||
hp->init = init;
|
||||
hp->dump = dump;
|
||||
hp->interrupt = interrupt;
|
||||
|
|
Loading…
Reference in a new issue