aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/range.c
diff options
context:
space:
mode:
authorStefano Stabellini <stefano.stabellini@eu.citrix.com>2010-07-21 13:32:37 -0400
committerThomas Gleixner <tglx@linutronix.de>2010-07-23 06:53:00 -0400
commitff4878089e1eaeac79d57878ad4ea32910fb4037 (patch)
tree0e2f78629117a2ca1eff77c673ce364bb4cc32a6 /kernel/range.c
parent087b255a2b43f417af83cb44e0bb02507f36b7fe (diff)
x86: Do not try to disable hpet if it hasn't been initialized before
hpet_disable is called unconditionally on machine reboot if hpet support is compiled in the kernel. hpet_disable only checks if the machine is hpet capable but doesn't make sure that hpet has been initialized. [ tglx: Made it a one liner and removed the redundant hpet_address check ] Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com> Acked-by: Venkatesh Pallipadi <venki@google.com> LKML-Reference: <alpine.DEB.2.00.1007211726240.22235@kaball-desktop> Cc: stable@kernel.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/range.c')
0 files changed, 0 insertions, 0 deletions
>92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506


























                                                                               
                     


                    

                                






















































































































































































































                                                                                                   

                                                          









                                                           

                                                                




                                                                      























































































































































































                                                                                                                 
























                                                       
                                                          




























                                                       
/*
 * Copyright 2012 Red Hat Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 */
/*
 * Authors: Dave Airlie <airlied@redhat.com>
 */
#include <drm/drmP.h>
#include "ast_drv.h"


#include <drm/drm_fb_helper.h>
#include <drm/drm_crtc_helper.h>

#include "ast_dram_tables.h"

void ast_set_index_reg_mask(struct ast_private *ast,
			    uint32_t base, uint8_t index,
			    uint8_t mask, uint8_t val)
{
	u8 tmp;
	ast_io_write8(ast, base, index);
	tmp = (ast_io_read8(ast, base + 1) & mask) | val;
	ast_set_index_reg(ast, base, index, tmp);
}

uint8_t ast_get_index_reg(struct ast_private *ast,
			  uint32_t base, uint8_t index)
{
	uint8_t ret;
	ast_io_write8(ast, base, index);
	ret = ast_io_read8(ast, base + 1);
	return ret;
}

uint8_t ast_get_index_reg_mask(struct ast_private *ast,
			       uint32_t base, uint8_t index, uint8_t mask)
{
	uint8_t ret;
	ast_io_write8(ast, base, index);
	ret = ast_io_read8(ast, base + 1) & mask;
	return ret;
}


static int ast_detect_chip(struct drm_device *dev)
{
	struct ast_private *ast = dev->dev_private;

	if (dev->pdev->device == PCI_CHIP_AST1180) {
		ast->chip = AST1100;
		DRM_INFO("AST 1180 detected\n");
	} else {
		if (dev->pdev->revision >= 0x20) {
			ast->chip = AST2300;
			DRM_INFO("AST 2300 detected\n");
		} else if (dev->pdev->revision >= 0x10) {
			uint32_t data;
			ast_write32(ast, 0xf004, 0x1e6e0000);
			ast_write32(ast, 0xf000, 0x1);

			data = ast_read32(ast, 0x1207c);
			switch (data & 0x0300) {
			case 0x0200:
				ast->chip = AST1100;
				DRM_INFO("AST 1100 detected\n");
				break;
			case 0x0100:
				ast->chip = AST2200;
				DRM_INFO("AST 2200 detected\n");
				break;
			case 0x0000:
				ast->chip = AST2150;
				DRM_INFO("AST 2150 detected\n");
				break;
			default:
				ast->chip = AST2100;
				DRM_INFO("AST 2100 detected\n");
				break;
			}
			ast->vga2_clone = false;
		} else {
			ast->chip = 2000;
			DRM_INFO("AST 2000 detected\n");
		}
	}
	return 0;
}

static int ast_get_dram_info(struct drm_device *dev)
{
	struct ast_private *ast = dev->dev_private;
	uint32_t data, data2;
	uint32_t denum, num, div, ref_pll;

	ast_write32(ast, 0xf004, 0x1e6e0000);
	ast_write32(ast, 0xf000, 0x1);


	ast_write32(ast, 0x10000, 0xfc600309);

	do {
		;
	} while (ast_read32(ast, 0x10000) != 0x01);
	data = ast_read32(ast, 0x10004);

	if (data & 0x400)
		ast->dram_bus_width = 16;
	else
		ast->dram_bus_width = 32;

	if (ast->chip == AST2300) {
		switch (data & 0x03) {
		case 0:
			ast->dram_type = AST_DRAM_512Mx16;
			break;
		default:
		case 1:
			ast->dram_type = AST_DRAM_1Gx16;
			break;
		case 2:
			ast->dram_type = AST_DRAM_2Gx16;
			break;
		case 3:
			ast->dram_type = AST_DRAM_4Gx16;
			break;
		}
	} else {
		switch (data & 0x0c) {
		case 0:
		case 4:
			ast->dram_type = AST_DRAM_512Mx16;
			break;
		case 8:
			if (data & 0x40)
				ast->dram_type = AST_DRAM_1Gx16;
			else
				ast->dram_type = AST_DRAM_512Mx32;
			break;
		case 0xc:
			ast->dram_type = AST_DRAM_1Gx32;
			break;
		}
	}

	data = ast_read32(ast, 0x10120);
	data2 = ast_read32(ast, 0x10170);
	if (data2 & 0x2000)
		ref_pll = 14318;
	else
		ref_pll = 12000;

	denum = data & 0x1f;
	num = (data & 0x3fe0) >> 5;
	data = (data & 0xc000) >> 14;
	switch (data) {
	case 3:
		div = 0x4;
		break;
	case 2:
	case 1:
		div = 0x2;
		break;
	default:
		div = 0x1;
		break;
	}
	ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000);
	return 0;
}

uint32_t ast_get_max_dclk(struct drm_device *dev, int bpp)
{
	struct ast_private *ast = dev->dev_private;
	uint32_t dclk, jreg;
	uint32_t dram_bus_width, mclk, dram_bandwidth, actual_dram_bandwidth, dram_efficency = 500;

	dram_bus_width = ast->dram_bus_width;
	mclk = ast->mclk;

	if (ast->chip == AST2100 ||
	    ast->chip == AST1100 ||
	    ast->chip == AST2200 ||
	    ast->chip == AST2150 ||
	    ast->dram_bus_width == 16)
		dram_efficency = 600;
	else if (ast->chip == AST2300)
		dram_efficency = 400;

	dram_bandwidth = mclk * dram_bus_width * 2 / 8;
	actual_dram_bandwidth = dram_bandwidth * dram_efficency / 1000;

	if (ast->chip == AST1180)
		dclk = actual_dram_bandwidth / ((bpp + 1) / 8);
	else {
		jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
		if ((jreg & 0x08) && (ast->chip == AST2000))
			dclk = actual_dram_bandwidth / ((bpp + 1 + 16) / 8);
		else if ((jreg & 0x08) && (bpp == 8))
			dclk = actual_dram_bandwidth / ((bpp + 1 + 24) / 8);
		else
			dclk = actual_dram_bandwidth / ((bpp + 1) / 8);
	}

	if (ast->chip == AST2100 ||
	    ast->chip == AST2200 ||
	    ast->chip == AST2300 ||
	    ast->chip == AST1180) {
		if (dclk > 200)
			dclk = 200;
	} else {
		if (dclk > 165)
			dclk = 165;
	}

	return dclk;
}

static void ast_user_framebuffer_destroy(struct drm_framebuffer *fb)
{
	struct ast_framebuffer *ast_fb = to_ast_framebuffer(fb);
	if (ast_fb->obj)
		drm_gem_object_unreference_unlocked(ast_fb->obj);

	drm_framebuffer_cleanup(fb);
	kfree(fb);
}

static const struct drm_framebuffer_funcs ast_fb_funcs = {
	.destroy = ast_user_framebuffer_destroy,
};


int ast_framebuffer_init(struct drm_device *dev,
			 struct ast_framebuffer *ast_fb,
			 struct drm_mode_fb_cmd2 *mode_cmd,
			 struct drm_gem_object *obj)
{
	int ret;

	drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd);
	ast_fb->obj = obj;
	ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs);
	if (ret) {
		DRM_ERROR("framebuffer init failed %d\n", ret);
		return ret;
	}
	return 0;
}

static struct drm_framebuffer *
ast_user_framebuffer_create(struct drm_device *dev,
	       struct drm_file *filp,
	       struct drm_mode_fb_cmd2 *mode_cmd)
{
	struct drm_gem_object *obj;
	struct ast_framebuffer *ast_fb;
	int ret;

	obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]);
	if (obj == NULL)
		return ERR_PTR(-ENOENT);

	ast_fb = kzalloc(sizeof(*ast_fb), GFP_KERNEL);
	if (!ast_fb) {
		drm_gem_object_unreference_unlocked(obj);
		return ERR_PTR(-ENOMEM);
	}

	ret = ast_framebuffer_init(dev, ast_fb, mode_cmd, obj);
	if (ret) {
		drm_gem_object_unreference_unlocked(obj);
		kfree(ast_fb);
		return ERR_PTR(ret);
	}
	return &ast_fb->base;
}

static const struct drm_mode_config_funcs ast_mode_funcs = {
	.fb_create = ast_user_framebuffer_create,
};

static u32 ast_get_vram_info(struct drm_device *dev)
{
	struct ast_private *ast = dev->dev_private;
	u8 jreg;

	ast_open_key(ast);

	jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xaa, 0xff);
	switch (jreg & 3) {
	case 0: return AST_VIDMEM_SIZE_8M;
	case 1: return AST_VIDMEM_SIZE_16M;
	case 2: return AST_VIDMEM_SIZE_32M;
	case 3: return AST_VIDMEM_SIZE_64M;
	}
	return AST_VIDMEM_DEFAULT_SIZE;
}

int ast_driver_load(struct drm_device *dev, unsigned long flags)
{
	struct ast_private *ast;
	int ret = 0;

	ast = kzalloc(sizeof(struct ast_private), GFP_KERNEL);
	if (!ast)
		return -ENOMEM;

	dev->dev_private = ast;
	ast->dev = dev;

	ast->regs = pci_iomap(dev->pdev, 1, 0);
	if (!ast->regs) {
		ret = -EIO;
		goto out_free;
	}
	ast->ioregs = pci_iomap(dev->pdev, 2, 0);
	if (!ast->ioregs) {
		ret = -EIO;
		goto out_free;
	}

	ast_detect_chip(dev);

	if (ast->chip != AST1180) {
		ast_get_dram_info(dev);
		ast->vram_size = ast_get_vram_info(dev);
		DRM_INFO("dram %d %d %d %08x\n", ast->mclk, ast->dram_type, ast->dram_bus_width, ast->vram_size);
	}

	ret = ast_mm_init(ast);
	if (ret)
		goto out_free;

	drm_mode_config_init(dev);

	dev->mode_config.funcs = (void *)&ast_mode_funcs;
	dev->mode_config.min_width = 0;
	dev->mode_config.min_height = 0;
	dev->mode_config.preferred_depth = 24;
	dev->mode_config.prefer_shadow = 1;

	if (ast->chip == AST2100 ||
	    ast->chip == AST2200 ||
	    ast->chip == AST2300 ||
	    ast->chip == AST1180) {
		dev->mode_config.max_width = 1920;
		dev->mode_config.max_height = 2048;
	} else {
		dev->mode_config.max_width = 1600;
		dev->mode_config.max_height = 1200;
	}

	ret = ast_mode_init(dev);
	if (ret)
		goto out_free;

	ret = ast_fbdev_init(dev);
	if (ret)
		goto out_free;

	return 0;
out_free:
	kfree(ast);
	dev->dev_private = NULL;
	return ret;
}

int ast_driver_unload(struct drm_device *dev)
{
	struct ast_private *ast = dev->dev_private;

	ast_mode_fini(dev);
	ast_fbdev_fini(dev);
	drm_mode_config_cleanup(dev);

	ast_mm_fini(ast);
	pci_iounmap(dev->pdev, ast->ioregs);
	pci_iounmap(dev->pdev, ast->regs);
	kfree(ast);
	return 0;
}

int ast_gem_create(struct drm_device *dev,
		   u32 size, bool iskernel,
		   struct drm_gem_object **obj)
{
	struct ast_bo *astbo;
	int ret;

	*obj = NULL;

	size = roundup(size, PAGE_SIZE);
	if (size == 0)
		return -EINVAL;

	ret = ast_bo_create(dev, size, 0, 0, &astbo);
	if (ret) {
		if (ret != -ERESTARTSYS)
			DRM_ERROR("failed to allocate GEM object\n");
		return ret;
	}
	*obj = &astbo->gem;
	return 0;
}

int ast_dumb_create(struct drm_file *file,
		    struct drm_device *dev,
		    struct drm_mode_create_dumb *args)
{
	int ret;
	struct drm_gem_object *gobj;
	u32 handle;

	args->pitch = args->width * ((args->bpp + 7) / 8);
	args->size = args->pitch * args->height;

	ret = ast_gem_create(dev, args->size, false,
			     &gobj);
	if (ret)
		return ret;

	ret = drm_gem_handle_create(file, gobj, &handle);
	drm_gem_object_unreference_unlocked(gobj);
	if (ret)
		return ret;

	args->handle = handle;
	return 0;
}

void ast_bo_unref(struct ast_bo **bo)
{
	struct ttm_buffer_object *tbo;

	if ((*bo) == NULL)
		return;

	tbo = &((*bo)->bo);
	ttm_bo_unref(&tbo);
	if (tbo == NULL)
		*bo = NULL;

}
void ast_gem_free_object(struct drm_gem_object *obj)
{
	struct ast_bo *ast_bo = gem_to_ast_bo(obj);

	if (!ast_bo)
		return;
	ast_bo_unref(&ast_bo);
}


static inline u64 ast_bo_mmap_offset(struct ast_bo *bo)
{
	return drm_vma_node_offset_addr(&bo->bo.vma_node);
}
int
ast_dumb_mmap_offset(struct drm_file *file,
		     struct drm_device *dev,
		     uint32_t handle,
		     uint64_t *offset)
{
	struct drm_gem_object *obj;
	int ret;
	struct ast_bo *bo;