File Index
Files and directories
Sign in
FILE

broadsheetfb.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/fbdev/broadsheetfb.c C
   1/*
   2 * broadsheetfb.c -- FB driver for E-Ink Broadsheet controller
   3 *
   4 * Copyright (C) 2008, Jaya Kumar
   5 *
   6 * This file is subject to the terms and conditions of the GNU General Public
   7 * License. See the file COPYING in the main directory of this archive for
   8 * more details.
   9 *
  10 * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven.
  11 *
  12 * This driver is written to be used with the Broadsheet display controller.
  13 *
  14 * It is intended to be architecture independent. A board specific driver
  15 * must be used to perform all the physical IO interactions.
  16 *
  17 */
  18
  19#include <linux/module.h>
  20#include <linux/kernel.h>
  21#include <linux/errno.h>
  22#include <linux/string.h>
  23#include <linux/mm.h>
  24#include <linux/slab.h>
  25#include <linux/vmalloc.h>
  26#include <linux/delay.h>
  27#include <linux/interrupt.h>
  28#include <linux/fb.h>
  29#include <linux/init.h>
  30#include <linux/platform_device.h>
  31#include <linux/list.h>
  32#include <linux/firmware.h>
  33#include <linux/uaccess.h>
  34
  35#include <video/broadsheetfb.h>
  36
  37/* track panel specific parameters */
  38struct panel_info {
  39	int w;
  40	int h;
  41	u16 sdcfg;
  42	u16 gdcfg;
  43	u16 lutfmt;
  44	u16 fsynclen;
  45	u16 fendfbegin;
  46	u16 lsynclen;
  47	u16 lendlbegin;
  48	u16 pixclk;
  49};
  50
  51/* table of panel specific parameters to be indexed into by the board drivers */
  52static struct panel_info panel_table[] = {
  53	{	/* standard 6" on TFT backplane */
  54		.w = 800,
  55		.h = 600,
  56		.sdcfg = (100 | (1 << 8) | (1 << 9)),
  57		.gdcfg = 2,
  58		.lutfmt = (4 | (1 << 7)),
  59		.fsynclen = 4,
  60		.fendfbegin = (10 << 8) | 4,
  61		.lsynclen = 10,
  62		.lendlbegin = (100 << 8) | 4,
  63		.pixclk = 6,
  64	},
  65	{	/* custom 3.7" flexible on PET or steel */
  66		.w = 320,
  67		.h = 240,
  68		.sdcfg = (67 | (0 << 8) | (0 << 9) | (0 << 10) | (0 << 12)),
  69		.gdcfg = 3,
  70		.lutfmt = (4 | (1 << 7)),
  71		.fsynclen = 0,
  72		.fendfbegin = (80 << 8) | 4,
  73		.lsynclen = 10,
  74		.lendlbegin = (80 << 8) | 20,
  75		.pixclk = 14,
  76	},
  77	{	/* standard 9.7" on TFT backplane */
  78		.w = 1200,
  79		.h = 825,
  80		.sdcfg = (100 | (1 << 8) | (1 << 9) | (0 << 10) | (0 << 12)),
  81		.gdcfg = 2,
  82		.lutfmt = (4 | (1 << 7)),
  83		.fsynclen = 0,
  84		.fendfbegin = (4 << 8) | 4,
  85		.lsynclen = 4,
  86		.lendlbegin = (60 << 8) | 10,
  87		.pixclk = 3,
  88	},
  89};
  90
  91#define DPY_W 800
  92#define DPY_H 600
  93
  94static struct fb_fix_screeninfo broadsheetfb_fix = {
  95	.id =		"broadsheetfb",
  96	.type =		FB_TYPE_PACKED_PIXELS,
  97	.visual =	FB_VISUAL_STATIC_PSEUDOCOLOR,
  98	.xpanstep =	0,
  99	.ypanstep =	0,
 100	.ywrapstep =	0,
 101	.line_length =	DPY_W,
 102	.accel =	FB_ACCEL_NONE,
 103};
 104
 105static struct fb_var_screeninfo broadsheetfb_var = {
 106	.xres		= DPY_W,
 107	.yres		= DPY_H,
 108	.xres_virtual	= DPY_W,
 109	.yres_virtual	= DPY_H,
 110	.bits_per_pixel	= 8,
 111	.grayscale	= 1,
 112	.red =		{ 0, 4, 0 },
 113	.green =	{ 0, 4, 0 },
 114	.blue =		{ 0, 4, 0 },
 115	.transp =	{ 0, 0, 0 },
 116};
 117
 118/* main broadsheetfb functions */
 119static void broadsheet_gpio_issue_data(struct broadsheetfb_par *par, u16 data)
 120{
 121	par->board->set_ctl(par, BS_WR, 0);
 122	par->board->set_hdb(par, data);
 123	par->board->set_ctl(par, BS_WR, 1);
 124}
 125
 126static void broadsheet_gpio_issue_cmd(struct broadsheetfb_par *par, u16 data)
 127{
 128	par->board->set_ctl(par, BS_DC, 0);
 129	broadsheet_gpio_issue_data(par, data);
 130}
 131
 132static void broadsheet_gpio_send_command(struct broadsheetfb_par *par, u16 data)
 133{
 134	par->board->wait_for_rdy(par);
 135
 136	par->board->set_ctl(par, BS_CS, 0);
 137	broadsheet_gpio_issue_cmd(par, data);
 138	par->board->set_ctl(par, BS_DC, 1);
 139	par->board->set_ctl(par, BS_CS, 1);
 140}
 141
 142static void broadsheet_gpio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
 143					int argc, u16 *argv)
 144{
 145	int i;
 146
 147	par->board->wait_for_rdy(par);
 148
 149	par->board->set_ctl(par, BS_CS, 0);
 150	broadsheet_gpio_issue_cmd(par, cmd);
 151	par->board->set_ctl(par, BS_DC, 1);
 152
 153	for (i = 0; i < argc; i++)
 154		broadsheet_gpio_issue_data(par, argv[i]);
 155	par->board->set_ctl(par, BS_CS, 1);
 156}
 157
 158static void broadsheet_mmio_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
 159				    int argc, u16 *argv)
 160{
 161	int i;
 162
 163	par->board->mmio_write(par, BS_MMIO_CMD, cmd);
 164
 165	for (i = 0; i < argc; i++)
 166		par->board->mmio_write(par, BS_MMIO_DATA, argv[i]);
 167}
 168
 169static void broadsheet_send_command(struct broadsheetfb_par *par, u16 data)
 170{
 171	if (par->board->mmio_write)
 172		par->board->mmio_write(par, BS_MMIO_CMD, data);
 173	else
 174		broadsheet_gpio_send_command(par, data);
 175}
 176
 177static void broadsheet_send_cmdargs(struct broadsheetfb_par *par, u16 cmd,
 178				    int argc, u16 *argv)
 179{
 180	if (par->board->mmio_write)
 181		broadsheet_mmio_send_cmdargs(par, cmd, argc, argv);
 182	else
 183		broadsheet_gpio_send_cmdargs(par, cmd, argc, argv);
 184}
 185
 186static void broadsheet_gpio_burst_write(struct broadsheetfb_par *par, int size,
 187					u16 *data)
 188{
 189	int i;
 190	u16 tmp;
 191
 192	par->board->set_ctl(par, BS_CS, 0);
 193	par->board->set_ctl(par, BS_DC, 1);
 194
 195	for (i = 0; i < size; i++) {
 196		par->board->set_ctl(par, BS_WR, 0);
 197		tmp = (data[i] & 0x0F) << 4;
 198		tmp |= (data[i] & 0x0F00) << 4;
 199		par->board->set_hdb(par, tmp);
 200		par->board->set_ctl(par, BS_WR, 1);
 201	}
 202
 203	par->board->set_ctl(par, BS_CS, 1);
 204}
 205
 206static void broadsheet_mmio_burst_write(struct broadsheetfb_par *par, int size,
 207				   u16 *data)
 208{
 209	int i;
 210	u16 tmp;
 211
 212	for (i = 0; i < size; i++) {
 213		tmp = (data[i] & 0x0F) << 4;
 214		tmp |= (data[i] & 0x0F00) << 4;
 215		par->board->mmio_write(par, BS_MMIO_DATA, tmp);
 216	}
 217
 218}
 219
 220static void broadsheet_burst_write(struct broadsheetfb_par *par, int size,
 221				   u16 *data)
 222{
 223	if (par->board->mmio_write)
 224		broadsheet_mmio_burst_write(par, size, data);
 225	else
 226		broadsheet_gpio_burst_write(par, size, data);
 227}
 228
 229static u16 broadsheet_gpio_get_data(struct broadsheetfb_par *par)
 230{
 231	u16 res;
 232	/* wait for ready to go hi. (lo is busy) */
 233	par->board->wait_for_rdy(par);
 234
 235	/* cs lo, dc lo for cmd, we lo for each data, db as usual */
 236	par->board->set_ctl(par, BS_DC, 1);
 237	par->board->set_ctl(par, BS_CS, 0);
 238	par->board->set_ctl(par, BS_WR, 0);
 239
 240	res = par->board->get_hdb(par);
 241
 242	/* strobe wr */
 243	par->board->set_ctl(par, BS_WR, 1);
 244	par->board->set_ctl(par, BS_CS, 1);
 245
 246	return res;
 247}
 248
 249
 250static u16 broadsheet_get_data(struct broadsheetfb_par *par)
 251{
 252	if (par->board->mmio_read)
 253		return par->board->mmio_read(par);
 254	else
 255		return broadsheet_gpio_get_data(par);
 256}
 257
 258static void broadsheet_gpio_write_reg(struct broadsheetfb_par *par, u16 reg,
 259					u16 data)
 260{
 261	/* wait for ready to go hi. (lo is busy) */
 262	par->board->wait_for_rdy(par);
 263
 264	/* cs lo, dc lo for cmd, we lo for each data, db as usual */
 265	par->board->set_ctl(par, BS_CS, 0);
 266
 267	broadsheet_gpio_issue_cmd(par, BS_CMD_WR_REG);
 268
 269	par->board->set_ctl(par, BS_DC, 1);
 270
 271	broadsheet_gpio_issue_data(par, reg);
 272	broadsheet_gpio_issue_data(par, data);
 273
 274	par->board->set_ctl(par, BS_CS, 1);
 275}
 276
 277static void broadsheet_mmio_write_reg(struct broadsheetfb_par *par, u16 reg,
 278				 u16 data)
 279{
 280	par->board->mmio_write(par, BS_MMIO_CMD, BS_CMD_WR_REG);
 281	par->board->mmio_write(par, BS_MMIO_DATA, reg);
 282	par->board->mmio_write(par, BS_MMIO_DATA, data);
 283
 284}
 285
 286static void broadsheet_write_reg(struct broadsheetfb_par *par, u16 reg,
 287					u16 data)
 288{
 289	if (par->board->mmio_write)
 290		broadsheet_mmio_write_reg(par, reg, data);
 291	else
 292		broadsheet_gpio_write_reg(par, reg, data);
 293}
 294
 295static void broadsheet_write_reg32(struct broadsheetfb_par *par, u16 reg,
 296					u32 data)
 297{
 298	broadsheet_write_reg(par, reg, cpu_to_le32(data) & 0xFFFF);
 299	broadsheet_write_reg(par, reg + 2, (cpu_to_le32(data) >> 16) & 0xFFFF);
 300}
 301
 302
 303static u16 broadsheet_read_reg(struct broadsheetfb_par *par, u16 reg)
 304{
 305	broadsheet_send_cmdargs(par, BS_CMD_RD_REG, 1, &reg);
 306	par->board->wait_for_rdy(par);
 307	return broadsheet_get_data(par);
 308}
 309
 310/* functions for waveform manipulation */
 311static int is_broadsheet_pll_locked(struct broadsheetfb_par *par)
 312{
 313	return broadsheet_read_reg(par, 0x000A) & 0x0001;
 314}
 315
 316static int broadsheet_setup_plls(struct broadsheetfb_par *par)
 317{
 318	int retry_count = 0;
 319	u16 tmp;
 320
 321	/* disable arral saemipu mode */
 322	broadsheet_write_reg(par, 0x0006, 0x0000);
 323
 324	broadsheet_write_reg(par, 0x0010, 0x0004);
 325	broadsheet_write_reg(par, 0x0012, 0x5949);
 326	broadsheet_write_reg(par, 0x0014, 0x0040);
 327	broadsheet_write_reg(par, 0x0016, 0x0000);
 328
 329	do {
 330		if (retry_count++ > 100)
 331			return -ETIMEDOUT;
 332		mdelay(1);
 333	} while (!is_broadsheet_pll_locked(par));
 334
 335	tmp = broadsheet_read_reg(par, 0x0006);
 336	tmp &= ~0x1;
 337	broadsheet_write_reg(par, 0x0006, tmp);
 338
 339	return 0;
 340}
 341
 342static int broadsheet_setup_spi(struct broadsheetfb_par *par)
 343{
 344
 345	broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1));
 346	broadsheet_write_reg(par, 0x0208, 0x0001);
 347
 348	return 0;
 349}
 350
 351static int broadsheet_setup_spiflash(struct broadsheetfb_par *par,
 352						u16 *orig_sfmcd)
 353{
 354
 355	*orig_sfmcd = broadsheet_read_reg(par, 0x0204);
 356	broadsheet_write_reg(par, 0x0208, 0);
 357	broadsheet_write_reg(par, 0x0204, 0);
 358	broadsheet_write_reg(par, 0x0204, ((3 << 3) | 1));
 359
 360	return 0;
 361}
 362
 363static int broadsheet_spiflash_wait_for_bit(struct broadsheetfb_par *par,
 364						u16 reg, int bitnum, int val,
 365						int timeout)
 366{
 367	u16 tmp;
 368
 369	do {
 370		tmp = broadsheet_read_reg(par, reg);
 371		if (((tmp >> bitnum) & 1) == val)
 372			return 0;
 373		mdelay(1);
 374	} while (timeout--);
 375
 376	return -ETIMEDOUT;
 377}
 378
 379static int broadsheet_spiflash_write_byte(struct broadsheetfb_par *par, u8 data)
 380{
 381	broadsheet_write_reg(par, 0x0202, (data | 0x100));
 382
 383	return broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);
 384}
 385
 386static int broadsheet_spiflash_read_byte(struct broadsheetfb_par *par, u8 *data)
 387{
 388	int err;
 389	u16 tmp;
 390
 391	broadsheet_write_reg(par, 0x0202, 0);
 392
 393	err = broadsheet_spiflash_wait_for_bit(par, 0x0206, 3, 0, 100);
 394	if (err)
 395		return err;
 396
 397	tmp = broadsheet_read_reg(par, 0x200);
 398
 399	*data = tmp & 0xFF;
 400
 401	return 0;
 402}
 403
 404static int broadsheet_spiflash_wait_for_status(struct broadsheetfb_par *par,
 405								int timeout)
 406{
 407	u8 tmp;
 408	int err;
 409
 410	do {
 411		broadsheet_write_reg(par, 0x0208, 1);
 412
 413		err = broadsheet_spiflash_write_byte(par, 0x05);
 414		if (err)
 415			goto failout;
 416
 417		err = broadsheet_spiflash_read_byte(par, &tmp);
 418		if (err)
 419			goto failout;
 420
 421		broadsheet_write_reg(par, 0x0208, 0);
 422
 423		if (!(tmp & 0x1))
 424			return 0;
 425
 426		mdelay(5);
 427	} while (timeout--);
 428
 429	dev_err(par->info->device, "Timed out waiting for spiflash status\n");
 430	return -ETIMEDOUT;
 431
 432failout:
 433	broadsheet_write_reg(par, 0x0208, 0);
 434	return err;
 435}
 436
 437static int broadsheet_spiflash_op_on_address(struct broadsheetfb_par *par,
 438							u8 op, u32 addr)
 439{
 440	int i;
 441	u8 tmp;
 442	int err;
 443
 444	broadsheet_write_reg(par, 0x0208, 1);
 445
 446	err = broadsheet_spiflash_write_byte(par, op);
 447	if (err)
 448		return err;
 449
 450	for (i = 2; i >= 0; i--) {
 451		tmp = ((addr >> (i * 8)) & 0xFF);
 452		err = broadsheet_spiflash_write_byte(par, tmp);
 453		if (err)
 454			return err;
 455	}
 456
 457	return err;
 458}
 459
 460static int broadsheet_verify_spiflash(struct broadsheetfb_par *par,
 461						int *flash_type)
 462{
 463	int err = 0;
 464	u8 sig;
 465
 466	err = broadsheet_spiflash_op_on_address(par, 0xAB, 0x00000000);
 467	if (err)
 468		goto failout;
 469
 470	err = broadsheet_spiflash_read_byte(par, &sig);
 471	if (err)
 472		goto failout;
 473
 474	if ((sig != 0x10) && (sig != 0x11)) {
 475		dev_err(par->info->device, "Unexpected flash type\n");
 476		err = -EINVAL;
 477		goto failout;
 478	}
 479
 480	*flash_type = sig;
 481
 482failout:
 483	broadsheet_write_reg(par, 0x0208, 0);
 484	return err;
 485}
 486
 487static int broadsheet_setup_for_wfm_write(struct broadsheetfb_par *par,
 488					u16 *initial_sfmcd, int *flash_type)
 489
 490{
 491	int err;
 492
 493	err = broadsheet_setup_plls(par);
 494	if (err)
 495		return err;
 496
 497	broadsheet_write_reg(par, 0x0106, 0x0203);
 498
 499	err = broadsheet_setup_spi(par);
 500	if (err)
 501		return err;
 502
 503	err = broadsheet_setup_spiflash(par, initial_sfmcd);
 504	if (err)
 505		return err;
 506
 507	return broadsheet_verify_spiflash(par, flash_type);
 508}
 509
 510static int broadsheet_spiflash_write_control(struct broadsheetfb_par *par,
 511						int mode)
 512{
 513	int err;
 514
 515	broadsheet_write_reg(par, 0x0208, 1);
 516	if (mode)
 517		err = broadsheet_spiflash_write_byte(par, 0x06);
 518	else
 519		err = broadsheet_spiflash_write_byte(par, 0x04);
 520
 521	broadsheet_write_reg(par, 0x0208, 0);
 522	return err;
 523}
 524
 525static int broadsheet_spiflash_erase_sector(struct broadsheetfb_par *par,
 526						int addr)
 527{
 528	int err;
 529
 530	broadsheet_spiflash_write_control(par, 1);
 531
 532	err = broadsheet_spiflash_op_on_address(par, 0xD8, addr);
 533
 534	broadsheet_write_reg(par, 0x0208, 0);
 535
 536	if (err)
 537		return err;
 538
 539	err = broadsheet_spiflash_wait_for_status(par, 1000);
 540
 541	return err;
 542}
 543
 544static int broadsheet_spiflash_read_range(struct broadsheetfb_par *par,
 545						int addr, int size, char *data)
 546{
 547	int err;
 548	int i;
 549
 550	err = broadsheet_spiflash_op_on_address(par, 0x03, addr);
 551	if (err)
 552		goto failout;
 553
 554	for (i = 0; i < size; i++) {
 555		err = broadsheet_spiflash_read_byte(par, &data[i]);
 556		if (err)
 557			goto failout;
 558	}
 559
 560failout:
 561	broadsheet_write_reg(par, 0x0208, 0);
 562	return err;
 563}
 564
 565#define BS_SPIFLASH_PAGE_SIZE 256
 566static int broadsheet_spiflash_write_page(struct broadsheetfb_par *par,
 567						int addr, const char *data)
 568{
 569	int err;
 570	int i;
 571
 572	broadsheet_spiflash_write_control(par, 1);
 573
 574	err = broadsheet_spiflash_op_on_address(par, 0x02, addr);
 575	if (err)
 576		goto failout;
 577
 578	for (i = 0; i < BS_SPIFLASH_PAGE_SIZE; i++) {
 579		err = broadsheet_spiflash_write_byte(par, data[i]);
 580		if (err)
 581			goto failout;
 582	}
 583
 584	broadsheet_write_reg(par, 0x0208, 0);
 585
 586	err = broadsheet_spiflash_wait_for_status(par, 100);
 587
 588failout:
 589	return err;
 590}
 591
 592static int broadsheet_spiflash_write_sector(struct broadsheetfb_par *par,
 593				int addr, const char *data, int sector_size)
 594{
 595	int i;
 596	int err;
 597
 598	for (i = 0; i < sector_size; i += BS_SPIFLASH_PAGE_SIZE) {
 599		err = broadsheet_spiflash_write_page(par, addr + i, &data[i]);
 600		if (err)
 601			return err;
 602	}
 603	return 0;
 604}
 605
 606/*
 607 * The caller must guarantee that the data to be rewritten is entirely
 608 * contained within this sector. That is, data_start_addr + data_len
 609 * must be less than sector_start_addr + sector_size.
 610 */
 611static int broadsheet_spiflash_rewrite_sector(struct broadsheetfb_par *par,
 612					int sector_size, int data_start_addr,
 613					int data_len, const char *data)
 614{
 615	int err;
 616	char *sector_buffer;
 617	int tail_start_addr;
 618	int start_sector_addr;
 619
 620	sector_buffer = kzalloc(sector_size, GFP_KERNEL);
 621	if (!sector_buffer)
 622		return -ENOMEM;
 623
 624	/* the start address of the sector is the 0th byte of that sector */
 625	start_sector_addr = (data_start_addr / sector_size) * sector_size;
 626
 627	/*
 628	 * check if there is head data that we need to readback into our sector
 629	 * buffer first
 630	 */
 631	if (data_start_addr != start_sector_addr) {
 632		/*
 633		 * we need to read every byte up till the start address of our
 634		 * data and we put it into our sector buffer.
 635		 */
 636		err = broadsheet_spiflash_read_range(par, start_sector_addr,
 637						data_start_addr, sector_buffer);
 638		if (err)
 639			goto out;
 640	}
 641
 642	/* now we copy our data into the right place in the sector buffer */
 643	memcpy(sector_buffer + data_start_addr, data, data_len);
 644
 645	/*
 646	 * now we check if there is a tail section of the sector that we need to
 647	 * readback.
 648	 */
 649	tail_start_addr = (data_start_addr + data_len) % sector_size;
 650
 651	if (tail_start_addr) {
 652		int tail_len;
 653
 654		tail_len = sector_size - tail_start_addr;
 655
 656		/* now we read this tail into our sector buffer */
 657		err = broadsheet_spiflash_read_range(par, tail_start_addr,
 658			tail_len, sector_buffer + tail_start_addr);
 659		if (err)
 660			goto out;
 661	}
 662
 663	/* if we got here we have the full sector that we want to rewrite. */
 664
 665	/* first erase the sector */
 666	err = broadsheet_spiflash_erase_sector(par, start_sector_addr);
 667	if (err)
 668		goto out;
 669
 670	/* now write it */
 671	err = broadsheet_spiflash_write_sector(par, start_sector_addr,
 672					sector_buffer, sector_size);
 673out:
 674	kfree(sector_buffer);
 675	return err;
 676}
 677
 678static int broadsheet_write_spiflash(struct broadsheetfb_par *par, u32 wfm_addr,
 679				const u8 *wfm, int bytecount, int flash_type)
 680{
 681	int sector_size;
 682	int err;
 683	int cur_addr;
 684	int writecount;
 685	int maxlen;
 686	int offset = 0;
 687
 688	switch (flash_type) {
 689	case 0x10:
 690		sector_size = 32*1024;
 691		break;
 692	case 0x11:
 693	default:
 694		sector_size = 64*1024;
 695		break;
 696	}
 697
 698	while (bytecount) {
 699		cur_addr = wfm_addr + offset;
 700		maxlen = roundup(cur_addr, sector_size) - cur_addr;
 701		writecount = min(bytecount, maxlen);
 702
 703		err = broadsheet_spiflash_rewrite_sector(par, sector_size,
 704				cur_addr, writecount, wfm + offset);
 705		if (err)
 706			return err;
 707
 708		offset += writecount;
 709		bytecount -= writecount;
 710	}
 711
 712	return 0;
 713}
 714
 715static int broadsheet_store_waveform_to_spiflash(struct broadsheetfb_par *par,
 716						const u8 *wfm, size_t wfm_size)
 717{
 718	int err = 0;
 719	u16 initial_sfmcd = 0;
 720	int flash_type = 0;
 721
 722	err = broadsheet_setup_for_wfm_write(par, &initial_sfmcd, &flash_type);
 723	if (err)
 724		goto failout;
 725
 726	err = broadsheet_write_spiflash(par, 0x886, wfm, wfm_size, flash_type);
 727
 728failout:
 729	broadsheet_write_reg(par, 0x0204, initial_sfmcd);
 730	return err;
 731}
 732
 733static ssize_t broadsheet_loadstore_waveform(struct device *dev,
 734						struct device_attribute *attr,
 735						const char *buf, size_t len)
 736{
 737	int err;
 738	struct fb_info *info = dev_get_drvdata(dev);
 739	struct broadsheetfb_par *par = info->par;
 740	const struct firmware *fw_entry;
 741
 742	if (len < 1)
 743		return -EINVAL;
 744
 745	err = request_firmware(&fw_entry, "broadsheet.wbf", dev);
 746	if (err < 0) {
 747		dev_err(dev, "Failed to get broadsheet waveform\n");
 748		goto err_failed;
 749	}
 750
 751	/* try to enforce reasonable min max on waveform */
 752	if ((fw_entry->size < 8*1024) || (fw_entry->size > 64*1024)) {
 753		dev_err(dev, "Invalid waveform\n");
 754		err = -EINVAL;
 755		goto err_fw;
 756	}
 757
 758	mutex_lock(&(par->io_lock));
 759	err = broadsheet_store_waveform_to_spiflash(par, fw_entry->data,
 760							fw_entry->size);
 761
 762	mutex_unlock(&(par->io_lock));
 763	if (err < 0) {
 764		dev_err(dev, "Failed to store broadsheet waveform\n");
 765		goto err_fw;
 766	}
 767
 768	dev_info(dev, "Stored broadsheet waveform, size %zd\n", fw_entry->size);
 769
 770	err = len;
 771
 772err_fw:
 773	release_firmware(fw_entry);
 774err_failed:
 775	return err;
 776}
 777static DEVICE_ATTR(loadstore_waveform, S_IWUSR, NULL,
 778			broadsheet_loadstore_waveform);
 779
 780/* upper level functions that manipulate the display and other stuff */
 781static void broadsheet_init_display(struct broadsheetfb_par *par)
 782{
 783	u16 args[5];
 784	int xres = par->info->var.xres;
 785	int yres = par->info->var.yres;
 786
 787	args[0] = panel_table[par->panel_index].w;
 788	args[1] = panel_table[par->panel_index].h;
 789	args[2] = panel_table[par->panel_index].sdcfg;
 790	args[3] = panel_table[par->panel_index].gdcfg;
 791	args[4] = panel_table[par->panel_index].lutfmt;
 792	broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
 793
 794	/* did the controller really set it? */
 795	broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_CFG, 5, args);
 796
 797	args[0] = panel_table[par->panel_index].fsynclen;
 798	args[1] = panel_table[par->panel_index].fendfbegin;
 799	args[2] = panel_table[par->panel_index].lsynclen;
 800	args[3] = panel_table[par->panel_index].lendlbegin;
 801	args[4] = panel_table[par->panel_index].pixclk;
 802	broadsheet_send_cmdargs(par, BS_CMD_INIT_DSPE_TMG, 5, args);
 803
 804	broadsheet_write_reg32(par, 0x310, xres*yres*2);
 805
 806	/* setup waveform */
 807	args[0] = 0x886;
 808	args[1] = 0;
 809	broadsheet_send_cmdargs(par, BS_CMD_RD_WFM_INFO, 2, args);
 810
 811	broadsheet_send_command(par, BS_CMD_UPD_GDRV_CLR);
 812
 813	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
 814
 815	broadsheet_write_reg(par, 0x330, 0x84);
 816
 817	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
 818
 819	args[0] = (0x3 << 4);
 820	broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args);
 821
 822	args[0] = 0x154;
 823	broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
 824
 825	broadsheet_burst_write(par, (panel_table[par->panel_index].w *
 826					panel_table[par->panel_index].h)/2,
 827					(u16 *)par->info->screen_buffer);
 828
 829	broadsheet_send_command(par, BS_CMD_LD_IMG_END);
 830
 831	args[0] = 0x4300;
 832	broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
 833
 834	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
 835
 836	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
 837
 838	par->board->wait_for_rdy(par);
 839}
 840
 841static void broadsheet_identify(struct broadsheetfb_par *par)
 842{
 843	u16 rev, prc;
 844	struct device *dev = par->info->device;
 845
 846	rev = broadsheet_read_reg(par, BS_REG_REV);
 847	prc = broadsheet_read_reg(par, BS_REG_PRC);
 848	dev_info(dev, "Broadsheet Rev 0x%x, Product Code 0x%x\n", rev, prc);
 849
 850	if (prc != 0x0047)
 851		dev_warn(dev, "Unrecognized Broadsheet Product Code\n");
 852	if (rev != 0x0100)
 853		dev_warn(dev, "Unrecognized Broadsheet Revision\n");
 854}
 855
 856static void broadsheet_init(struct broadsheetfb_par *par)
 857{
 858	broadsheet_send_command(par, BS_CMD_INIT_SYS_RUN);
 859	/* the controller needs a second */
 860	msleep(1000);
 861	broadsheet_init_display(par);
 862}
 863
 864static void broadsheetfb_dpy_update_pages(struct broadsheetfb_par *par,
 865						u16 y1, u16 y2)
 866{
 867	u16 args[5];
 868	unsigned char *buf = par->info->screen_buffer;
 869
 870	mutex_lock(&(par->io_lock));
 871	/* y1 must be a multiple of 4 so drop the lower bits */
 872	y1 &= 0xFFFC;
 873	/* y2 must be a multiple of 4 , but - 1 so up the lower bits */
 874	y2 |= 0x0003;
 875
 876	args[0] = 0x3 << 4;
 877	args[1] = 0;
 878	args[2] = y1;
 879	args[3] = cpu_to_le16(par->info->var.xres);
 880	args[4] = y2;
 881	broadsheet_send_cmdargs(par, BS_CMD_LD_IMG_AREA, 5, args);
 882
 883	args[0] = 0x154;
 884	broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
 885
 886	buf += y1 * par->info->var.xres;
 887	broadsheet_burst_write(par, ((1 + y2 - y1) * par->info->var.xres)/2,
 888				(u16 *) buf);
 889
 890	broadsheet_send_command(par, BS_CMD_LD_IMG_END);
 891
 892	args[0] = 0x4300;
 893	broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
 894
 895	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
 896
 897	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
 898
 899	par->board->wait_for_rdy(par);
 900	mutex_unlock(&(par->io_lock));
 901
 902}
 903
 904static void broadsheetfb_dpy_update(struct broadsheetfb_par *par)
 905{
 906	u16 args[5];
 907
 908	mutex_lock(&(par->io_lock));
 909	args[0] = 0x3 << 4;
 910	broadsheet_send_cmdargs(par, BS_CMD_LD_IMG, 1, args);
 911
 912	args[0] = 0x154;
 913	broadsheet_send_cmdargs(par, BS_CMD_WR_REG, 1, args);
 914	broadsheet_burst_write(par, (panel_table[par->panel_index].w *
 915					panel_table[par->panel_index].h)/2,
 916					(u16 *)par->info->screen_buffer);
 917
 918	broadsheet_send_command(par, BS_CMD_LD_IMG_END);
 919
 920	args[0] = 0x4300;
 921	broadsheet_send_cmdargs(par, BS_CMD_UPD_FULL, 1, args);
 922
 923	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_TRG);
 924
 925	broadsheet_send_command(par, BS_CMD_WAIT_DSPE_FREND);
 926
 927	par->board->wait_for_rdy(par);
 928	mutex_unlock(&(par->io_lock));
 929}
 930
 931/* this is called back from the deferred io workqueue */
 932static void broadsheetfb_dpy_deferred_io(struct fb_info *info, struct list_head *pagereflist)
 933{
 934	u16 y1 = 0, h = 0;
 935	unsigned long prev_offset = ULONG_MAX;
 936	struct fb_deferred_io_pageref *pageref;
 937	int h_inc;
 938	u16 yres = info->var.yres;
 939	u16 xres = info->var.xres;
 940
 941	/* height increment is fixed per page */
 942	h_inc = DIV_ROUND_UP(PAGE_SIZE , xres);
 943
 944	/* walk the written page list and swizzle the data */
 945	list_for_each_entry(pageref, pagereflist, list) {
 946		if (prev_offset == ULONG_MAX) {
 947			/* just starting so assign first page */
 948			y1 = pageref->offset / xres;
 949			h = h_inc;
 950		} else if ((prev_offset + PAGE_SIZE) == pageref->offset) {
 951			/* this page is consecutive so increase our height */
 952			h += h_inc;
 953		} else {
 954			/* page not consecutive, issue previous update first */
 955			broadsheetfb_dpy_update_pages(info->par, y1, y1 + h);
 956			/* start over with our non consecutive page */
 957			y1 = pageref->offset / xres;
 958			h = h_inc;
 959		}
 960		prev_offset = pageref->offset;
 961	}
 962
 963	/* if we still have any pages to update we do so now */
 964	if (h >= yres) {
 965		/* its a full screen update, just do it */
 966		broadsheetfb_dpy_update(info->par);
 967	} else {
 968		broadsheetfb_dpy_update_pages(info->par, y1,
 969						min((u16) (y1 + h), yres));
 970	}
 971}
 972
 973static void broadsheetfb_defio_damage_range(struct fb_info *info, off_t off, size_t len)
 974{
 975	struct broadsheetfb_par *par = info->par;
 976
 977	broadsheetfb_dpy_update(par);
 978}
 979
 980static void broadsheetfb_defio_damage_area(struct fb_info *info, u32 x, u32 y,
 981					   u32 width, u32 height)
 982{
 983	struct broadsheetfb_par *par = info->par;
 984
 985	broadsheetfb_dpy_update(par);
 986}
 987
 988FB_GEN_DEFAULT_DEFERRED_SYSMEM_OPS(broadsheetfb,
 989				   broadsheetfb_defio_damage_range,
 990				   broadsheetfb_defio_damage_area)
 991
 992static const struct fb_ops broadsheetfb_ops = {
 993	.owner	= THIS_MODULE,
 994	FB_DEFAULT_DEFERRED_OPS(broadsheetfb),
 995};
 996
 997static struct fb_deferred_io broadsheetfb_defio = {
 998	.delay			= HZ/4,
 999	.sort_pagereflist	= true,
1000	.deferred_io		= broadsheetfb_dpy_deferred_io,
1001};
1002
1003static int broadsheetfb_probe(struct platform_device *dev)
1004{
1005	struct fb_info *info;
1006	struct broadsheet_board *board;
1007	int retval = -ENOMEM;
1008	int videomemorysize;
1009	unsigned char *videomemory;
1010	struct broadsheetfb_par *par;
1011	int i;
1012	int dpyw, dpyh;
1013	int panel_index;
1014
1015	/* pick up board specific routines */
1016	board = dev->dev.platform_data;
1017	if (!board)
1018		return -EINVAL;
1019
1020	/* try to count device specific driver, if can't, platform recalls */
1021	if (!try_module_get(board->owner))
1022		return -ENODEV;
1023
1024	info = framebuffer_alloc(sizeof(struct broadsheetfb_par), &dev->dev);
1025	if (!info)
1026		goto err;
1027
1028	switch (board->get_panel_type()) {
1029	case 37:
1030		panel_index = 1;
1031		break;
1032	case 97:
1033		panel_index = 2;
1034		break;
1035	case 6:
1036	default:
1037		panel_index = 0;
1038		break;
1039	}
1040
1041	dpyw = panel_table[panel_index].w;
1042	dpyh = panel_table[panel_index].h;
1043
1044	videomemorysize = roundup((dpyw*dpyh), PAGE_SIZE);
1045
1046	videomemory = vzalloc(videomemorysize);
1047	if (!videomemory)
1048		goto err_fb_rel;
1049
1050	info->screen_buffer = videomemory;
1051	info->fbops = &broadsheetfb_ops;
1052
1053	broadsheetfb_var.xres = dpyw;
1054	broadsheetfb_var.yres = dpyh;
1055	broadsheetfb_var.xres_virtual = dpyw;
1056	broadsheetfb_var.yres_virtual = dpyh;
1057	info->var = broadsheetfb_var;
1058
1059	broadsheetfb_fix.line_length = dpyw;
1060	info->fix = broadsheetfb_fix;
1061	info->fix.smem_len = videomemorysize;
1062	par = info->par;
1063	par->panel_index = panel_index;
1064	par->info = info;
1065	par->board = board;
1066	par->write_reg = broadsheet_write_reg;
1067	par->read_reg = broadsheet_read_reg;
1068	init_waitqueue_head(&par->waitq);
1069
1070	mutex_init(&par->io_lock);
1071
1072	info->flags = FBINFO_VIRTFB;
1073
1074	info->fbdefio = &broadsheetfb_defio;
1075	fb_deferred_io_init(info);
1076
1077	retval = fb_alloc_cmap(&info->cmap, 16, 0);
1078	if (retval < 0) {
1079		dev_err(&dev->dev, "Failed to allocate colormap\n");
1080		goto err_vfree;
1081	}
1082
1083	/* set cmap */
1084	for (i = 0; i < 16; i++)
1085		info->cmap.red[i] = (((2*i)+1)*(0xFFFF))/32;
1086	memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*16);
1087	memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*16);
1088
1089	retval = par->board->setup_irq(info);
1090	if (retval < 0)
1091		goto err_cmap;
1092
1093	/* this inits the dpy */
1094	retval = board->init(par);
1095	if (retval < 0)
1096		goto err_free_irq;
1097
1098	broadsheet_identify(par);
1099
1100	broadsheet_init(par);
1101
1102	retval = register_framebuffer(info);
1103	if (retval < 0)
1104		goto err_free_irq;
1105
1106	platform_set_drvdata(dev, info);
1107
1108	retval = device_create_file(&dev->dev, &dev_attr_loadstore_waveform);
1109	if (retval < 0)
1110		goto err_unreg_fb;
1111
1112	fb_info(info, "Broadsheet frame buffer, using %dK of video memory\n",
1113		videomemorysize >> 10);
1114
1115
1116	return 0;
1117
1118err_unreg_fb:
1119	unregister_framebuffer(info);
1120err_free_irq:
1121	board->cleanup(par);
1122err_cmap:
1123	fb_dealloc_cmap(&info->cmap);
1124err_vfree:
1125	vfree(videomemory);
1126err_fb_rel:
1127	framebuffer_release(info);
1128err:
1129	module_put(board->owner);
1130	return retval;
1131
1132}
1133
1134static void broadsheetfb_remove(struct platform_device *dev)
1135{
1136	struct fb_info *info = platform_get_drvdata(dev);
1137
1138	if (info) {
1139		struct broadsheetfb_par *par = info->par;
1140
1141		device_remove_file(info->device, &dev_attr_loadstore_waveform);
1142		unregister_framebuffer(info);
1143		fb_deferred_io_cleanup(info);
1144		par->board->cleanup(par);
1145		fb_dealloc_cmap(&info->cmap);
1146		vfree(info->screen_buffer);
1147		module_put(par->board->owner);
1148		framebuffer_release(info);
1149	}
1150}
1151
1152static struct platform_driver broadsheetfb_driver = {
1153	.probe	= broadsheetfb_probe,
1154	.remove	= broadsheetfb_remove,
1155	.driver	= {
1156		.name	= "broadsheetfb",
1157	},
1158};
1159module_platform_driver(broadsheetfb_driver);
1160
1161MODULE_DESCRIPTION("fbdev driver for Broadsheet controller");
1162MODULE_AUTHOR("Jaya Kumar");
1163MODULE_LICENSE("GPL");
1164
1165MODULE_FIRMWARE("broadsheet.wbf");
~/ Read-only file preview.