Work continues on imxdisplay(4). New patch included below further configures HDMI/IPU/DI clocks.
Ian Index: conf/GENERIC =================================================================== RCS file: /cvs/src/sys/arch/armv7/conf/GENERIC,v retrieving revision 1.31 diff -u -p -r1.31 GENERIC --- conf/GENERIC 12 Jul 2016 19:17:49 -0000 1.31 +++ conf/GENERIC 5 Aug 2016 06:50:24 -0000 @@ -54,6 +54,8 @@ sdmmc* at imxesdhc? # SD/MMC bus imxahci* at fdt? # AHCI/SATA imxehci* at fdt? # EHCI usb* at imxehci? +imxdisplay* at fdt? # IPU/HDMI +wsdisplay* at imxdisplay? # OMAP3xxx/OMAP4xxx SoC omap0 at mainbus? Index: imx/files.imx =================================================================== RCS file: /cvs/src/sys/arch/armv7/imx/files.imx,v retrieving revision 1.15 diff -u -p -r1.15 files.imx --- imx/files.imx 12 Jul 2016 19:17:49 -0000 1.15 +++ imx/files.imx 5 Aug 2016 06:50:24 -0000 @@ -51,3 +51,8 @@ file arch/armv7/imx/imxesdhc.c imxesdhc device imxahci: scsi, atascsi attach imxahci at fdt file arch/armv7/imx/imxahci.c imxahci + +device imxdisplay: wsemuldisplaydev, rasops16 +attach imxdisplay at fdt +file arch/armv7/imx/imxdisplay.c imxdisplay + Index: imx/imxccm.c =================================================================== RCS file: /cvs/src/sys/arch/armv7/imx/imxccm.c,v retrieving revision 1.5 diff -u -p -r1.5 imxccm.c --- imx/imxccm.c 30 May 2015 08:09:19 -0000 1.5 +++ imx/imxccm.c 5 Aug 2016 06:50:24 -0000 @@ -75,6 +75,15 @@ #define CCM_ANALOG_PLL_USB2_SET 0x4024 #define CCM_ANALOG_PLL_USB2_CLR 0x4028 #define CCM_ANALOG_PLL_SYS 0x4030 +#define CCM_ANALOG_PLL_VIDEO 0x40A0 +#define CCM_ANALOG_PLL_VIDEO_SET 0x40A4 +#define CCM_ANALOG_PLL_VIDEO_CLR 0x40A8 +#define CCM_ANALOG_PLL_VIDEO_NUM 0x40B0 +#define CCM_ANALOG_PLL_VIDEO_NUM_SET 0x40B4 +#define CCM_ANALOG_PLL_VIDEO_NUM_CLR 0x40B8 +#define CCM_ANALOG_PLL_VIDEO_DENOM 0x40C0 +#define CCM_ANALOG_PLL_VIDEO_DENOM_SET 0x40C4 +#define CCM_ANALOG_PLL_VIDEO_DENOM_CLR 0x40C8 #define CCM_ANALOG_USB1_CHRG_DETECT 0x41b0 #define CCM_ANALOG_USB1_CHRG_DETECT_SET 0x41b4 #define CCM_ANALOG_USB1_CHRG_DETECT_CLR 0x41b8 @@ -108,12 +117,22 @@ #define CCM_CBCMR_PERIPH_CLK2_SEL_MASK 0x3 #define CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT 18 #define CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK 0x3 +#define CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK (7 << 6) +#define CCM_CHSCCDR_IPU1_DI0_PODF_MASK (7 << 3) +#define CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK (7 << 0) +#define CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_SHIFT 6 +#define CCM_CHSCCDR_IPU1_DI0_PODF_SHIFT 3 +#define CCM_CHSCCDR_IPU1_DI0_CLK_SEL_SHIFT 0 #define CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x) ((x) + 15) #define CCM_CSCDR1_USDHCx_CLK_SEL_MASK 0x1 #define CCM_CSCDR1_USDHCx_PODF_MASK 0x7 #define CCM_CSCDR1_UART_PODF_MASK 0x7 #define CCM_CCGR1_ENET (3 << 10) #define CCM_CCGR2_I2C(x) (3 << (6 + 2*x)) +#define CCM_CCGR2_HDMI_TX_ISFRCLK (3 << 4) +#define CCM_CCGR2_HDMI_TX_IAHBCLK (3 << 0) +#define CCM_CCGR3_IPU1_IPU_CLK_MASK (3 << 0) +#define CCM_CCGR3_IPU1_DI0_CLK_MASK (3 << 2) #define CCM_CCGR4_125M_PCIE (3 << 0) #define CCM_CCGR5_100M_SATA (3 << 4) #define CCM_CCGR6_USBOH3 (3 << 0) @@ -151,6 +170,14 @@ #define CCM_PMU_MISC1_LVDSCLK1_CLK_SEL_MASK (0x1f << 0) #define CCM_PMU_MISC1_LVDSCLK1_OBEN (1 << 10) #define CCM_PMU_MISC1_LVDSCLK1_IBEN (1 << 12) +#define CCM_ANALOG_PLL_VIDEO_ENABLE (1 << 13) +#define CCM_ANALOG_PLL_VIDEO_LOCK (1U << 31) +#define CCM_ANALOG_PLL_VIDEO_POWERDOWN (1 << 12) +#define CCM_ANALOG_PLL_VIDEO_BYPASS (1 << 16) +#define CCM_ANALOG_PLL_VIDEO_DIV_SELECT (127 << 0) +#define CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT (3 << 19) +#define CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_SHIFT 19 + #define HCLK_FREQ 24000 #define PLL3_80M 80000 @@ -220,9 +247,12 @@ void imxccm_disable_usb2_chrg_detect(voi void imxccm_enable_pll_usb1(void); void imxccm_enable_pll_usb2(void); void imxccm_enable_pll_enet(void); +void imxccm_enable_pll_video(void); void imxccm_enable_enet(void); void imxccm_enable_sata(void); void imxccm_enable_pcie(void); +void imxccm_enable_hdmi(void); +void imxccm_enable_ipu(void); struct cfattach imxccm_ca = { sizeof (struct imxccm_softc), NULL, imxccm_attach @@ -518,6 +548,29 @@ imxccm_enable_pll_enet(void) } void +imxccm_enable_pll_video(void) +{ + struct imxccm_softc *sc = imxccm_sc; + + /* Set PLL to 455MHz */ + HSET4(sc, CCM_ANALOG_PLL_VIDEO, CCM_ANALOG_PLL_VIDEO_POWERDOWN); + HCLR4(sc, CCM_ANALOG_PLL_VIDEO, CCM_ANALOG_PLL_VIDEO_DIV_SELECT); + HSET4(sc, CCM_ANALOG_PLL_VIDEO, 0x25); + HCLR4(sc, CCM_ANALOG_PLL_VIDEO, CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT); + HSET4(sc, CCM_ANALOG_PLL_VIDEO, 0x01 << CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_SHIFT); + HCLR4(sc, CCM_ANALOG_PLL_VIDEO_NUM, 0x3FFFFFFF); + HSET4(sc, CCM_ANALOG_PLL_VIDEO_NUM, 0xB); + HCLR4(sc, CCM_ANALOG_PLL_VIDEO_DENOM, 0x3FFFFFFF); + HSET4(sc, CCM_ANALOG_PLL_VIDEO_DENOM, 0xC); + + HCLR4(sc, CCM_ANALOG_PLL_VIDEO, CCM_ANALOG_PLL_VIDEO_POWERDOWN); + while(!(HREAD4(sc, CCM_ANALOG_PLL_VIDEO) & CCM_ANALOG_PLL_VIDEO_LOCK)); + + HSET4(sc, CCM_ANALOG_PLL_VIDEO, CCM_ANALOG_PLL_VIDEO_ENABLE); + HCLR4(sc, CCM_ANALOG_PLL_VIDEO, CCM_ANALOG_PLL_VIDEO_BYPASS); +} + +void imxccm_enable_enet(void) { struct imxccm_softc *sc = imxccm_sc; @@ -554,6 +607,35 @@ imxccm_enable_pcie(void) HWRITE4(sc, CCM_ANALOG_PLL_ENET_SET, CCM_ANALOG_PLL_ENET_125M_PCIE); HSET4(sc, CCM_CCGR4, CCM_CCGR4_125M_PCIE); +} + +void +imxccm_enable_hdmi(void) +{ + struct imxccm_softc *sc = imxccm_sc; + + imxccm_enable_ipu(); + imxccm_enable_pll_video(); + + /* Set display interface clock to 65MHz */ + HCLR4(sc, CCM_CCGR2, CCM_CCGR3_IPU1_DI0_CLK_MASK); + HCLR4(sc, CCM_CHSCCDR, CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK); + HCLR4(sc, CCM_CHSCCDR, CCM_CHSCCDR_IPU1_DI0_PODF_MASK); + HCLR4(sc, CCM_CHSCCDR, CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK); + HSET4(sc, CCM_CHSCCDR, 0x2 << CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_SHIFT); + HSET4(sc, CCM_CHSCCDR, 0x6 << CCM_CHSCCDR_IPU1_DI0_PODF_SHIFT); + HSET4(sc, CCM_CCGR2, CCM_CCGR3_IPU1_DI0_CLK_MASK); + + HSET4(sc, CCM_CCGR2, CCM_CCGR2_HDMI_TX_ISFRCLK); + HSET4(sc, CCM_CCGR2, CCM_CCGR2_HDMI_TX_IAHBCLK); +} + +void +imxccm_enable_ipu(void) +{ + struct imxccm_softc *sc = imxccm_sc; + + HSET4(sc, CCM_CCGR3, CCM_CCGR3_IPU1_IPU_CLK_MASK); } void Index: imx/imxccmvar.h =================================================================== RCS file: /cvs/src/sys/arch/armv7/imx/imxccmvar.h,v retrieving revision 1.2 diff -u -p -r1.2 imxccmvar.h --- imx/imxccmvar.h 30 May 2015 08:09:19 -0000 1.2 +++ imx/imxccmvar.h 5 Aug 2016 06:50:24 -0000 @@ -32,5 +32,6 @@ void imxccm_enable_pll_usb2(void); void imxccm_enable_enet(void); void imxccm_enable_sata(void); void imxccm_enable_pcie(void); +void imxccm_enable_hdmi(void); #endif /* IMXCCMVAR_H */ Index: imx/imxdisplay.c =================================================================== RCS file: imx/imxdisplay.c diff -N imx/imxdisplay.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ imx/imxdisplay.c 5 Aug 2016 06:50:24 -0000 @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2016 Ian Sutton <i...@kremlin.cc> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <machine/fdt.h> + +#include <dev/cons.h> +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_callbacks.h> +#include <dev/rasops/rasops.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/fdt.h> + +#include <armv7/imx/imxccmvar.h> + +struct imxdisplay_screen { + LIST_ENTRY(imxdisplay_screen) link; + + size_t buf_size; + size_t map_size; + void *buf_va; + int depth; + struct rasops_info rinfo; + +}; + +struct imxdisplay_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + struct rasops_info *ro; +}; + +int imxdisplay_match(struct device *, void *, void *a); +void imxdisplay_attach(struct device *, struct device *, void *); +int imxdisplay_activate(struct device *, int); + +int imxdisplay_ioctl(void *, u_long, caddr_t, int, struct proc *); +int imxdisplay_alloc_screen(void *, const struct wsscreen_descr *, + void **, int *, int *, long *); +void imxdisplay_free_screen(void *, void *); +int imxdisplay_show_screen(void *, void *, int, + void (*)(void *, int, int), void *); +void imxdisplay_doswitch(void *, void *); +int imxdisplay_load_font(void *, void *, struct wsdisplay_font *); +int imxdisplay_list_font(void *, struct wsdisplay_font *); +int imxdisplay_getchar(void *, int, int, struct wsdisplay_charcell *); +void imxdisplay_burner(void *, u_int, u_int); +paddr_t imxdisplay_mmap(void *, off_t, int); + +void imxdisplay_setup_rasops(struct imxdisplay_softc *, struct rasops_info *); + +struct wsdisplay_accessops imxdisplay_accessops = { + .ioctl = imxdisplay_ioctl, + .mmap = imxdisplay_mmap, + .alloc_screen = imxdisplay_alloc_screen, + .free_screen = imxdisplay_free_screen, + .show_screen = imxdisplay_show_screen, + .getchar = imxdisplay_getchar, + .load_font = imxdisplay_load_font, + .list_font = imxdisplay_list_font, + .burn_screen = imxdisplay_burner +}; + +struct cfattach imxdisplay_ca = { + sizeof(struct imxdisplay_softc), imxdisplay_match, imxdisplay_attach, NULL, + imxdisplay_activate +}; + +struct cfdriver imxdisplay_cd = { + NULL, "imxdisplay", DV_DULL +}; + +struct rasops_info imxdisplay_ri; +struct wsscreen_descr imxdisplay_stdscreen = { + "std" +}; + +const struct wsscreen_descr *imxdisplay_scrlist[] = { + &imxdisplay_stdscreen, +}; + +struct wsscreen_list imxdisplay_screenlist = { + nitems(imxdisplay_scrlist), imxdisplay_scrlist +}; + +int +imxdisplay_match(struct device *parent, void *v, void *aux) +{ + struct fdt_attach_args *faa = aux; + return OF_is_compatible(faa->fa_node, "fsl,imx6q-hdmi"); +} + +void +imxdisplay_attach(struct device *parent, struct device *self, void *args) +{ + struct imxdisplay_softc *sc = (struct imxdisplay_softc *) self; + struct fdt_attach_args *faa = args; + struct wsemuldisplaydev_attach_args wsaa; + struct rasops_info *ri = &imxdisplay_ri; + + sc->sc_iot = faa->fa_iot; + if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, + faa->fa_reg[1].size, 0, &sc->sc_ioh)) + panic("%s: bus_space_map failed!", __func__); + + imxccm_enable_hdmi(); + + printf("\n"); + + imxdisplay_setup_rasops(sc, ri); + sc->ro = ri; + + wsaa.console = 0; + wsaa.scrdata = &imxdisplay_screenlist; + wsaa.accessops = &imxdisplay_accessops; + wsaa.accesscookie = sc; + wsaa.defaultscreens = 0; + + printf("%s: %dx%d\n", sc->sc_dev.dv_xname, ri->ri_width, ri->ri_height); + + config_found(self, &wsaa, wsemuldisplaydevprint); +} + +void +imxdisplay_setup_rasops(struct imxdisplay_softc *sc, struct rasops_info *rinfo) +{ + /* XXX dummy data for now */ + rinfo->ri_depth = 16; + rinfo->ri_width = 240; + rinfo->ri_height = 322; + rinfo->ri_stride = 240 * 16; + + rasops_init(rinfo, 100, 100); +} + +int +imxdisplay_activate(struct device *self, int act) +{ + /* XXX */ + switch (act) { + case DVACT_SUSPEND: + break; + case DVACT_RESUME: + break; + } + + return 0; +} +int +imxdisplay_ioctl(void *sconf, u_long cmd, caddr_t data, int flat, struct proc *p) +{ + return -1; +} + +paddr_t +imxdisplay_mmap(void *sconf, off_t off, int prot) +{ + return -1; +} + +int +imxdisplay_alloc_screen(void *sconf, const struct wsscreen_descr *type, + void **cookiep, int *curxp, int *curyp, long *attrp) +{ + struct imxdisplay_softc *sc = sconf; + struct rasops_info *ri = sc->ro; + + return rasops_alloc_screen(ri, cookiep, curxp, curyp, attrp); +} + +void +imxdisplay_free_screen(void *sconf, void *cookie) +{ + struct imxdisplay_softc *sc = sconf; + struct rasops_info *ri = sc->ro; + + return rasops_free_screen(ri, cookie); +} + +int +imxdisplay_show_screen(void *sconf, void *cookie, int waitok, + void (*cb)(void *, int, int), void *cbarg) +{ + return (0); +} + +void +imxdisplay_doswitch(void *v, void *dummy) +{ +} + +int +imxdisplay_getchar(void *sconf, int row, int col, struct wsdisplay_charcell *cell) +{ + struct imxdisplay_softc *sc = sconf; + struct rasops_info *ri = sc->ro; + + return rasops_getchar(ri, row, col, cell); +} + +int +imxdisplay_load_font(void *sconf, void *cookie, struct wsdisplay_font *font) +{ + struct imxdisplay_softc *sc = sconf; + struct rasops_info *ri = sc->ro; + + return rasops_load_font(ri, cookie, font); +} + +int +imxdisplay_list_font(void *sconf, struct wsdisplay_font *font) +{ + struct imxdisplay_softc *sc = sconf; + struct rasops_info *ri = sc->ro; + + return rasops_list_font(ri, font); +} + +void +imxdisplay_burner(void *sconf, u_int on, u_int flags) +{ +}