Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

/* $NetBSD: ssdfbvar.h,v 1.2 2019/03/17 04:03:17 tnn Exp $ */

/*
 * Copyright (c) 2019 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Tobias Nygren.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * cfdata attachment flags
 */
#define SSDFB_ATTACH_FLAG_PRODUCT_MASK		0x000000ff
#define SSDFB_ATTACH_FLAG_UPSIDEDOWN		0x00000100
#define SSDFB_ATTACH_FLAG_INVERSE		0x00000200
#define SSDFB_ATTACH_FLAG_CONSOLE		0x00000400

/*
 * Fundamental commands
 * SSD1306 Rev 1.1 p.28
 * SH1106 Rev 0.1 p.19,20,22
 */
#define SSDFB_CMD_SET_CONTRAST_CONTROL		0x81
#define SSDFB_CMD_ENTIRE_DISPLAY_OFF		0xa4
#define SSDFB_CMD_ENTIRE_DISPLAY_ON		0xa5
#define SSDFB_CMD_SET_NORMAL_DISPLAY		0xa6
#define SSDFB_CMD_SET_INVERSE_DISPLAY		0xa7
#define SSDFB_CMD_SET_DISPLAY_OFF		0xae
#define SSDFB_CMD_SET_DISPLAY_ON		0xaf

/*
 * Scrolling commands; SSD1306 Rev 1.1 p. 28
 */
#define SSDFB_CMD_VERTICAL_AND_RIGHT_SCROLL	0x29
#define SSDFB_CMD_VERTICAL_AND_LEFT_SCROLL	0x2a
#define SSDFB_CMD_DEACTIVATE_SCROLL		0x2e
#define SSDFB_CMD_ACTIVATE_SCROLL		0x2f
#define SSDFB_CMD_SET_VERTICAL_SCROLL_AREA	0xa3

/*
 * Addressing commands
 * SSD1306 Rev 1.1 p.30
 * SH1106 Rev 0.1 p.18,22
 */
#define SSDFB_CMD_SET_LOWER_COLUMN_START_ADDRESS_BASE	0x00
#define SSDFB_CMD_SET_LOWER_COLUMN_START_ADDRESS_MAX	0x0f
#define SSDFB_CMD_SET_HIGHER_COLUMN_START_ADDRESS_BASE	0x10
#define SSDFB_CMD_SET_HIGHER_COLUMN_START_ADDRESS_MAX	0x1f
#define SSD1306_CMD_SET_MEMORY_ADDRESSING_MODE		0x20
	#define SSD1306_MEMORY_ADDRESSING_MODE_HORIZONTAL 0x00
	#define SSD1306_MEMORY_ADDRESSING_MODE_VERTICAL	0x01
	#define SSD1306_MEMORY_ADDRESSING_MODE_PAGE	0x02
#define SSD1306_CMD_SET_COLUMN_ADDRESS			0x21
#define SSD1306_CMD_SET_PAGE_ADDRESS			0x22
#define SSDFB_CMD_SET_PAGE_START_ADDRESS_BASE		0xb0
#define SSDFB_CMD_SET_PAGE_START_ADDRESS_MAX		0xb7

/*
 * Resolution & hardware layout commands
 * SSD1306 Rev 1.1 p.31
 * SH1106 Rev 0.1 p.19,20,21,23
 */
#define SSDFB_CMD_SET_DISPLAY_START_LINE_BASE		0x40
#define SSDFB_CMD_SET_DISPLAY_START_LINE_MAX		0x7f
#define SSDFB_CMD_SET_SEGMENT_REMAP_NORMAL		0xa0
#define SSDFB_CMD_SET_SEGMENT_REMAP_REVERSE		0xa1
#define SSDFB_CMD_SET_MULTIPLEX_RATIO			0xa8
#define SSDFB_CMD_SET_COM_OUTPUT_DIRECTION_NORMAL	0xc0
#define SSDFB_CMD_SET_COM_OUTPUT_DIRECTION_REMAP	0xc8
#define SSDFB_CMD_SET_DISPLAY_OFFSET			0xd3
#define SSDFB_CMD_SET_COM_PINS_HARDWARE_CFG		0xda
	#define SSDFB_COM_PINS_A1_MASK			0x02
	#define SSDFB_COM_PINS_ALTERNATIVE_MASK		0x10
	#define SSDFB_COM_PINS_REMAP_MASK		0x20

/*
 * Timing & driving commands
 * SSD1306 Rev 1.1 p.32
 * SH1106 Rev 0.1 p.24,25,26
 */
#define SSDFB_CMD_SET_DISPLAY_CLOCK_RATIO		0xd5
	#define SSDFB_DISPLAY_CLOCK_DIVIDER_MASK	0x0f
	#define SSDFB_DISPLAY_CLOCK_DIVIDER_SHIFT	0
	#define SSDFB_DISPLAY_CLOCK_OSCILLATOR_MASK	0xf0
	#define SSDFB_DISPLAY_CLOCK_OSCILLATOR_SHIFT	4
#define SSDFB_CMD_SET_PRECHARGE_PERIOD			0xd9
	#define SSDFB_PRECHARGE_MASK			0x0f
	#define SSDFB_PRECHARGE_SHIFT			0
	#define SSDFB_DISCHARGE_MASK			0xf0
	#define SSDFB_DISCHARGE_SHIFT			4
#define SSDFB_CMD_SET_VCOMH_DESELECT_LEVEL		0xdb
	#define SSD1306_VCOMH_DESELECT_LEVEL_0_65_VCC	0x00
	#define SSD1306_VCOMH_DESELECT_LEVEL_0_77_VCC	0x20
	#define SSD1306_VCOMH_DESELECT_LEVEL_0_83_VCC	0x30
	#define SH1106_VCOMH_DESELECT_LEVEL_DEFAULT	0x35

/*
 * Misc commands
 * SSD1306 Rev 1.1 p.32
 * SH1106 Rev 0.1 p.27,28
 */
#define SSDFB_CMD_NOP					0xe3
#define SH1106_CMD_READ_MODIFY_WRITE			0xe0
#define SH1106_CMD_READ_MODIFY_WRITE_CANCEL		0xee

/*
 * Charge pump commands
 * SSD1306 App Note Rev 0.4 p.3
 * SH1106 V0.1 p.18
 */
#define SSD1306_CMD_SET_CHARGE_PUMP			0x8d
	#define SSD1306_CHARGE_PUMP_ENABLE		0x14
	#define SSD1306_CHARGE_PUMP_DISABE		0x10
#define SH1106_CMD_SET_CHARGE_PUMP_7V4			0x30
#define SH1106_CMD_SET_CHARGE_PUMP_8V0			0x31
#define SH1106_CMD_SET_CHARGE_PUMP_8V4			0x32
#define SH1106_CMD_SET_CHARGE_PUMP_9V0			0x33

/*
 * DC-DC commands
 * SH1106 V0.1 p.18
 */
#define SH1106_CMD_SET_DC_DC				0xad
	#define SH1106_DC_DC_OFF			0x8a
	#define SH1106_DC_DC_ON				0x8b

typedef enum {
	SSDFB_CONTROLLER_UNKNOWN=0,
	SSDFB_CONTROLLER_SSD1306=1,
	SSDFB_CONTROLLER_SH1106=2,
} ssdfb_controller_id_t;

typedef enum {
	SSDFB_PRODUCT_UNKNOWN=0,
	SSDFB_PRODUCT_SSD1306_GENERIC=1,
	SSDFB_PRODUCT_SH1106_GENERIC=2,
	SSDFB_PRODUCT_ADAFRUIT_931=3,
	SSDFB_PRODUCT_ADAFRUIT_938=4,
} ssdfb_product_id_t;

#define SSDFB_I2C_DEFAULT_ADDR		0x3c
#define SSDFB_I2C_ALTERNATIVE_ADDR	0x3d

/* Co bit has different behaviour in SSD1306 and SH1106 */
#define SSDFB_I2C_CTRL_BYTE_CONTINUATION_MASK	__BIT(7)
#define SSDFB_I2C_CTRL_BYTE_DATA_MASK		__BIT(6)

union ssdfb_block {
	uint8_t		col[8];
	uint64_t	raw;
};

struct ssdfb_product {
	ssdfb_product_id_t		p_product_id;
	ssdfb_controller_id_t		p_controller_id;
	const char			*p_name;
	int				p_width;
	int				p_height;
	int				p_panel_shift;
	uint8_t				p_fosc;
	uint8_t				p_fosc_div;
	uint8_t				p_precharge;
	uint8_t				p_discharge;
	uint8_t				p_compin_cfg;
	uint8_t				p_vcomh_deselect_level;
	uint8_t				p_default_contrast;
	uint8_t				p_multiplex_ratio;
	uint8_t				p_chargepump_cmd;
	uint8_t				p_chargepump_arg;
};

struct ssdfb_softc {
	device_t			sc_dev;
	const struct ssdfb_product	*sc_p;

	/* wscons & rasops state */
	u_int				sc_mode;
	int				sc_fontcookie;
	struct wsdisplay_font		*sc_font;
	struct wsscreen_descr		sc_screen_descr;
	const struct wsscreen_descr	*sc_screens[1];
	struct wsscreen_list		sc_screenlist;
	struct rasops_info		sc_ri;
	size_t				sc_ri_bits_len;
	struct wsdisplay_emulops	sc_orig_riops;
	int				sc_nscreens;
	device_t			sc_wsdisplay;
	bool				sc_is_console;
	bool				sc_usepoll;

	/* hardware state */
	bool				sc_upsidedown;
	bool				sc_inverse;
	uint8_t				sc_contrast;
	bool				sc_display_on;
	union ssdfb_block		*sc_gddram;
	size_t				sc_gddram_len;

	/* damage tracking */
	lwp_t				*sc_thread;
	kcondvar_t			sc_cond;
	kmutex_t			sc_cond_mtx;
	bool				sc_detaching;
	int				sc_backoff;
	bool				sc_modified;
	struct uvm_object		*sc_uobj;

	/* reference to bus-specific code */
	void	*sc_cookie;
	int	(*sc_cmd)(void *, uint8_t *, size_t, bool);
	int	(*sc_transfer_rect)(void *, uint8_t, uint8_t, uint8_t, uint8_t,
				    uint8_t *, size_t, bool);
};

void	ssdfb_attach(struct ssdfb_softc *, int flags);
int	ssdfb_detach(struct ssdfb_softc *);