source "drivers/gpu/drm/gma500/Kconfig"
 
 source "drivers/gpu/drm/udl/Kconfig"
+
+source "drivers/gpu/drm/ast/Kconfig"
+
 
 obj-$(CONFIG_DRM_EXYNOS) +=exynos/
 obj-$(CONFIG_DRM_GMA500) += gma500/
 obj-$(CONFIG_DRM_UDL) += udl/
+obj-$(CONFIG_DRM_AST) += ast/
 obj-y                  += i2c/
 
--- /dev/null
+config DRM_AST
+       tristate "AST server chips"
+       depends on DRM && PCI && EXPERIMENTAL
+       select DRM_TTM
+       select FB_SYS_COPYAREA
+       select FB_SYS_FILLRECT
+       select FB_SYS_IMAGEBLIT
+       select DRM_KMS_HELPER
+       help
+        Say yes for experimental AST GPU driver. Do not enable
+        this driver without having a working -modesetting,
+        and a version of AST that knows to fail if KMS
+        is bound to the driver. These GPUs are commonly found
+        in server chipsets.
+
 
--- /dev/null
+#
+# Makefile for the drm device driver.  This driver provides support for the
+# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
+
+ccflags-y := -Iinclude/drm
+
+ast-y := ast_drv.o ast_main.o ast_mode.o ast_fb.o ast_ttm.o ast_post.o
+
+obj-$(CONFIG_DRM_AST) := ast.o
\ No newline at end of file
 
--- /dev/null
+#ifndef AST_DRAM_TABLES_H
+#define AST_DRAM_TABLES_H
+
+/* DRAM timing tables */
+struct ast_dramstruct {
+       u16 index;
+       u32 data;
+};
+
+static const struct ast_dramstruct ast2000_dram_table_data[] = {
+       { 0x0108, 0x00000000 },
+       { 0x0120, 0x00004a21 },
+       { 0xFF00, 0x00000043 },
+       { 0x0000, 0xFFFFFFFF },
+       { 0x0004, 0x00000089 },
+       { 0x0008, 0x22331353 },
+       { 0x000C, 0x0d07000b },
+       { 0x0010, 0x11113333 },
+       { 0x0020, 0x00110350 },
+       { 0x0028, 0x1e0828f0 },
+       { 0x0024, 0x00000001 },
+       { 0x001C, 0x00000000 },
+       { 0x0014, 0x00000003 },
+       { 0xFF00, 0x00000043 },
+       { 0x0018, 0x00000131 },
+       { 0x0014, 0x00000001 },
+       { 0xFF00, 0x00000043 },
+       { 0x0018, 0x00000031 },
+       { 0x0014, 0x00000001 },
+       { 0xFF00, 0x00000043 },
+       { 0x0028, 0x1e0828f1 },
+       { 0x0024, 0x00000003 },
+       { 0x002C, 0x1f0f28fb },
+       { 0x0030, 0xFFFFFE01 },
+       { 0xFFFF, 0xFFFFFFFF }
+};
+
+static const struct ast_dramstruct ast1100_dram_table_data[] = {
+       { 0x2000, 0x1688a8a8 },
+       { 0x2020, 0x000041f0 },
+       { 0xFF00, 0x00000043 },
+       { 0x0000, 0xfc600309 },
+       { 0x006C, 0x00909090 },
+       { 0x0064, 0x00050000 },
+       { 0x0004, 0x00000585 },
+       { 0x0008, 0x0011030f },
+       { 0x0010, 0x22201724 },
+       { 0x0018, 0x1e29011a },
+       { 0x0020, 0x00c82222 },
+       { 0x0014, 0x01001523 },
+       { 0x001C, 0x1024010d },
+       { 0x0024, 0x00cb2522 },
+       { 0x0038, 0xffffff82 },
+       { 0x003C, 0x00000000 },
+       { 0x0040, 0x00000000 },
+       { 0x0044, 0x00000000 },
+       { 0x0048, 0x00000000 },
+       { 0x004C, 0x00000000 },
+       { 0x0050, 0x00000000 },
+       { 0x0054, 0x00000000 },
+       { 0x0058, 0x00000000 },
+       { 0x005C, 0x00000000 },
+       { 0x0060, 0x032aa02a },
+       { 0x0064, 0x002d3000 },
+       { 0x0068, 0x00000000 },
+       { 0x0070, 0x00000000 },
+       { 0x0074, 0x00000000 },
+       { 0x0078, 0x00000000 },
+       { 0x007C, 0x00000000 },
+       { 0x0034, 0x00000001 },
+       { 0xFF00, 0x00000043 },
+       { 0x002C, 0x00000732 },
+       { 0x0030, 0x00000040 },
+       { 0x0028, 0x00000005 },
+       { 0x0028, 0x00000007 },
+       { 0x0028, 0x00000003 },
+       { 0x0028, 0x00000001 },
+       { 0x000C, 0x00005a08 },
+       { 0x002C, 0x00000632 },
+       { 0x0028, 0x00000001 },
+       { 0x0030, 0x000003c0 },
+       { 0x0028, 0x00000003 },
+       { 0x0030, 0x00000040 },
+       { 0x0028, 0x00000003 },
+       { 0x000C, 0x00005a21 },
+       { 0x0034, 0x00007c03 },
+       { 0x0120, 0x00004c41 },
+       { 0xffff, 0xffffffff },
+};
+
+static const struct ast_dramstruct ast2100_dram_table_data[] = {
+       { 0x2000, 0x1688a8a8 },
+       { 0x2020, 0x00004120 },
+       { 0xFF00, 0x00000043 },
+       { 0x0000, 0xfc600309 },
+       { 0x006C, 0x00909090 },
+       { 0x0064, 0x00070000 },
+       { 0x0004, 0x00000489 },
+       { 0x0008, 0x0011030f },
+       { 0x0010, 0x32302926 },
+       { 0x0018, 0x274c0122 },
+       { 0x0020, 0x00ce2222 },
+       { 0x0014, 0x01001523 },
+       { 0x001C, 0x1024010d },
+       { 0x0024, 0x00cb2522 },
+       { 0x0038, 0xffffff82 },
+       { 0x003C, 0x00000000 },
+       { 0x0040, 0x00000000 },
+       { 0x0044, 0x00000000 },
+       { 0x0048, 0x00000000 },
+       { 0x004C, 0x00000000 },
+       { 0x0050, 0x00000000 },
+       { 0x0054, 0x00000000 },
+       { 0x0058, 0x00000000 },
+       { 0x005C, 0x00000000 },
+       { 0x0060, 0x0f2aa02a },
+       { 0x0064, 0x003f3005 },
+       { 0x0068, 0x02020202 },
+       { 0x0070, 0x00000000 },
+       { 0x0074, 0x00000000 },
+       { 0x0078, 0x00000000 },
+       { 0x007C, 0x00000000 },
+       { 0x0034, 0x00000001 },
+       { 0xFF00, 0x00000043 },
+       { 0x002C, 0x00000942 },
+       { 0x0030, 0x00000040 },
+       { 0x0028, 0x00000005 },
+       { 0x0028, 0x00000007 },
+       { 0x0028, 0x00000003 },
+       { 0x0028, 0x00000001 },
+       { 0x000C, 0x00005a08 },
+       { 0x002C, 0x00000842 },
+       { 0x0028, 0x00000001 },
+       { 0x0030, 0x000003c0 },
+       { 0x0028, 0x00000003 },
+       { 0x0030, 0x00000040 },
+       { 0x0028, 0x00000003 },
+       { 0x000C, 0x00005a21 },
+       { 0x0034, 0x00007c03 },
+       { 0x0120, 0x00005061 },
+       { 0xffff, 0xffffffff },
+};
+
+#endif
 
--- /dev/null
+/*
+ * 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 <linux/module.h>
+#include <linux/console.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc_helper.h"
+
+#include "ast_drv.h"
+
+int ast_modeset = -1;
+
+MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
+module_param_named(modeset, ast_modeset, int, 0400);
+
+#define PCI_VENDOR_ASPEED 0x1a03
+
+static struct drm_driver driver;
+
+#define AST_VGA_DEVICE(id, info) {             \
+       .class = PCI_BASE_CLASS_DISPLAY << 16,  \
+       .class_mask = 0xff0000,                 \
+       .vendor = PCI_VENDOR_ASPEED,                    \
+       .device = id,                           \
+       .subvendor = PCI_ANY_ID,                \
+       .subdevice = PCI_ANY_ID,                \
+       .driver_data = (unsigned long) info }
+
+static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
+       AST_VGA_DEVICE(PCI_CHIP_AST2000, NULL),
+       AST_VGA_DEVICE(PCI_CHIP_AST2100, NULL),
+       /*      AST_VGA_DEVICE(PCI_CHIP_AST1180, NULL), - don't bind to 1180 for now */
+       {0, 0, 0},
+};
+
+MODULE_DEVICE_TABLE(pci, pciidlist);
+
+static int __devinit
+ast_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       return drm_get_pci_dev(pdev, ent, &driver);
+}
+
+static void
+ast_pci_remove(struct pci_dev *pdev)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+
+       drm_put_dev(dev);
+}
+
+
+
+static int ast_drm_freeze(struct drm_device *dev)
+{
+       drm_kms_helper_poll_disable(dev);
+
+       pci_save_state(dev->pdev);
+
+       console_lock();
+       ast_fbdev_set_suspend(dev, 1);
+       console_unlock();
+       return 0;
+}
+
+static int ast_drm_thaw(struct drm_device *dev)
+{
+       int error = 0;
+
+       ast_post_gpu(dev);
+
+       drm_mode_config_reset(dev);
+       mutex_lock(&dev->mode_config.mutex);
+       drm_helper_resume_force_mode(dev);
+       mutex_unlock(&dev->mode_config.mutex);
+
+       console_lock();
+       ast_fbdev_set_suspend(dev, 0);
+       console_unlock();
+       return error;
+}
+
+static int ast_drm_resume(struct drm_device *dev)
+{
+       int ret;
+
+       if (pci_enable_device(dev->pdev))
+               return -EIO;
+
+       ret = ast_drm_thaw(dev);
+       if (ret)
+               return ret;
+
+       drm_kms_helper_poll_enable(dev);
+       return 0;
+}
+
+static int ast_pm_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *ddev = pci_get_drvdata(pdev);
+       int error;
+
+       error = ast_drm_freeze(ddev);
+       if (error)
+               return error;
+
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+       return 0;
+}
+static int ast_pm_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *ddev = pci_get_drvdata(pdev);
+       return ast_drm_resume(ddev);
+}
+
+static int ast_pm_freeze(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *ddev = pci_get_drvdata(pdev);
+
+       if (!ddev || !ddev->dev_private)
+               return -ENODEV;
+       return ast_drm_freeze(ddev);
+
+}
+
+static int ast_pm_thaw(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *ddev = pci_get_drvdata(pdev);
+       return ast_drm_thaw(ddev);
+}
+
+static int ast_pm_poweroff(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *ddev = pci_get_drvdata(pdev);
+
+       return ast_drm_freeze(ddev);
+}
+
+static const struct dev_pm_ops ast_pm_ops = {
+       .suspend = ast_pm_suspend,
+       .resume = ast_pm_resume,
+       .freeze = ast_pm_freeze,
+       .thaw = ast_pm_thaw,
+       .poweroff = ast_pm_poweroff,
+       .restore = ast_pm_resume,
+};
+
+static struct pci_driver ast_pci_driver = {
+       .name = DRIVER_NAME,
+       .id_table = pciidlist,
+       .probe = ast_pci_probe,
+       .remove = ast_pci_remove,
+       .driver.pm = &ast_pm_ops,
+};
+
+static const struct file_operations ast_fops = {
+       .owner = THIS_MODULE,
+       .open = drm_open,
+       .release = drm_release,
+       .unlocked_ioctl = drm_ioctl,
+       .mmap = ast_mmap,
+       .poll = drm_poll,
+       .fasync = drm_fasync,
+       .read = drm_read,
+};
+
+static struct drm_driver driver = {
+       .driver_features = DRIVER_USE_MTRR | DRIVER_MODESET | DRIVER_GEM,
+       .dev_priv_size = 0,
+
+       .load = ast_driver_load,
+       .unload = ast_driver_unload,
+
+       .fops = &ast_fops,
+       .name = DRIVER_NAME,
+       .desc = DRIVER_DESC,
+       .date = DRIVER_DATE,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+       .patchlevel = DRIVER_PATCHLEVEL,
+
+       .gem_init_object = ast_gem_init_object,
+       .gem_free_object = ast_gem_free_object,
+       .dumb_create = ast_dumb_create,
+       .dumb_map_offset = ast_dumb_mmap_offset,
+       .dumb_destroy = ast_dumb_destroy,
+
+};
+
+static int __init ast_init(void)
+{
+       if (vgacon_text_force() && ast_modeset == -1)
+               return -EINVAL;
+
+       if (ast_modeset == 0)
+               return -EINVAL;
+       return drm_pci_init(&driver, &ast_pci_driver);
+}
+static void __exit ast_exit(void)
+{
+       drm_pci_exit(&driver, &ast_pci_driver);
+}
+
+module_init(ast_init);
+module_exit(ast_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
+
 
--- /dev/null
+/*
+ * 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>
+ */
+#ifndef __AST_DRV_H__
+#define __AST_DRV_H__
+
+#include "drm_fb_helper.h"
+
+#include "ttm/ttm_bo_api.h"
+#include "ttm/ttm_bo_driver.h"
+#include "ttm/ttm_placement.h"
+#include "ttm/ttm_memory.h"
+#include "ttm/ttm_module.h"
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+#define DRIVER_AUTHOR          "Dave Airlie"
+
+#define DRIVER_NAME            "ast"
+#define DRIVER_DESC            "AST"
+#define DRIVER_DATE            "20120228"
+
+#define DRIVER_MAJOR           0
+#define DRIVER_MINOR           1
+#define DRIVER_PATCHLEVEL      0
+
+#define PCI_CHIP_AST2000 0x2000
+#define PCI_CHIP_AST2100 0x2010
+#define PCI_CHIP_AST1180 0x1180
+
+
+enum ast_chip {
+       AST2000,
+       AST2100,
+       AST1100,
+       AST2200,
+       AST2150,
+       AST2300,
+       AST1180,
+};
+
+#define AST_DRAM_512Mx16 0
+#define AST_DRAM_1Gx16   1
+#define AST_DRAM_512Mx32 2
+#define AST_DRAM_1Gx32   3
+#define AST_DRAM_2Gx16   6
+#define AST_DRAM_4Gx16   7
+
+struct ast_fbdev;
+
+struct ast_private {
+       struct drm_device *dev;
+
+       void __iomem *regs;
+       void __iomem *ioregs;
+
+       enum ast_chip chip;
+       bool vga2_clone;
+       uint32_t dram_bus_width;
+       uint32_t dram_type;
+       uint32_t mclk;
+       uint32_t vram_size;
+
+       struct ast_fbdev *fbdev;
+
+       int fb_mtrr;
+
+       struct {
+               struct drm_global_reference mem_global_ref;
+               struct ttm_bo_global_ref bo_global_ref;
+               struct ttm_bo_device bdev;
+               atomic_t validate_sequence;
+       } ttm;
+
+       struct drm_gem_object *cursor_cache;
+       uint64_t cursor_cache_gpu_addr;
+       struct ttm_bo_kmap_obj cache_kmap;
+       int next_cursor;
+};
+
+int ast_driver_load(struct drm_device *dev, unsigned long flags);
+int ast_driver_unload(struct drm_device *dev);
+
+struct ast_gem_object;
+
+#define AST_IO_AR_PORT_WRITE           (0x40)
+#define AST_IO_MISC_PORT_WRITE         (0x42)
+#define AST_IO_SEQ_PORT                        (0x44)
+#define AST_DAC_INDEX_READ             (0x3c7)
+#define AST_IO_DAC_INDEX_WRITE         (0x48)
+#define AST_IO_DAC_DATA                        (0x49)
+#define AST_IO_GR_PORT                 (0x4E)
+#define AST_IO_CRTC_PORT               (0x54)
+#define AST_IO_INPUT_STATUS1_READ      (0x5A)
+#define AST_IO_MISC_PORT_READ          (0x4C)
+
+#define __ast_read(x) \
+static inline u##x ast_read##x(struct ast_private *ast, u32 reg) { \
+u##x val = 0;\
+val = ioread##x(ast->regs + reg); \
+return val;\
+}
+
+__ast_read(8);
+__ast_read(16);
+__ast_read(32)
+
+#define __ast_io_read(x) \
+static inline u##x ast_io_read##x(struct ast_private *ast, u32 reg) { \
+u##x val = 0;\
+val = ioread##x(ast->ioregs + reg); \
+return val;\
+}
+
+__ast_io_read(8);
+__ast_io_read(16);
+__ast_io_read(32);
+
+#define __ast_write(x) \
+static inline void ast_write##x(struct ast_private *ast, u32 reg, u##x val) {\
+       iowrite##x(val, ast->regs + reg);\
+       }
+
+__ast_write(8);
+__ast_write(16);
+__ast_write(32);
+
+#define __ast_io_write(x) \
+static inline void ast_io_write##x(struct ast_private *ast, u32 reg, u##x val) {\
+       iowrite##x(val, ast->ioregs + reg);\
+       }
+
+__ast_io_write(8);
+__ast_io_write(16);
+#undef __ast_io_write
+
+static inline void ast_set_index_reg(struct ast_private *ast,
+                                    uint32_t base, uint8_t index,
+                                    uint8_t val)
+{
+       ast_io_write16(ast, base, ((u16)val << 8) | index);
+}
+
+void ast_set_index_reg_mask(struct ast_private *ast,
+                           uint32_t base, uint8_t index,
+                           uint8_t mask, uint8_t val);
+uint8_t ast_get_index_reg(struct ast_private *ast,
+                         uint32_t base, uint8_t index);
+uint8_t ast_get_index_reg_mask(struct ast_private *ast,
+                              uint32_t base, uint8_t index, uint8_t mask);
+
+static inline void ast_open_key(struct ast_private *ast)
+{
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xA1, 0xFF, 0x04);
+}
+
+#define AST_VIDMEM_SIZE_8M    0x00800000
+#define AST_VIDMEM_SIZE_16M   0x01000000
+#define AST_VIDMEM_SIZE_32M   0x02000000
+#define AST_VIDMEM_SIZE_64M   0x04000000
+#define AST_VIDMEM_SIZE_128M  0x08000000
+
+#define AST_VIDMEM_DEFAULT_SIZE AST_VIDMEM_SIZE_8M
+
+#define AST_MAX_HWC_WIDTH 64
+#define AST_MAX_HWC_HEIGHT 64
+
+#define AST_HWC_SIZE                (AST_MAX_HWC_WIDTH*AST_MAX_HWC_HEIGHT*2)
+#define AST_HWC_SIGNATURE_SIZE      32
+
+#define AST_DEFAULT_HWC_NUM 2
+/* define for signature structure */
+#define AST_HWC_SIGNATURE_CHECKSUM  0x00
+#define AST_HWC_SIGNATURE_SizeX     0x04
+#define AST_HWC_SIGNATURE_SizeY     0x08
+#define AST_HWC_SIGNATURE_X         0x0C
+#define AST_HWC_SIGNATURE_Y         0x10
+#define AST_HWC_SIGNATURE_HOTSPOTX  0x14
+#define AST_HWC_SIGNATURE_HOTSPOTY  0x18
+
+
+struct ast_i2c_chan {
+       struct i2c_adapter adapter;
+       struct drm_device *dev;
+       struct i2c_algo_bit_data bit;
+};
+
+struct ast_connector {
+       struct drm_connector base;
+       struct ast_i2c_chan *i2c;
+};
+
+struct ast_crtc {
+       struct drm_crtc base;
+       u8 lut_r[256], lut_g[256], lut_b[256];
+       struct drm_gem_object *cursor_bo;
+       uint64_t cursor_addr;
+       int cursor_width, cursor_height;
+       u8 offset_x, offset_y;
+};
+
+struct ast_encoder {
+       struct drm_encoder base;
+};
+
+struct ast_framebuffer {
+       struct drm_framebuffer base;
+       struct drm_gem_object *obj;
+};
+
+struct ast_fbdev {
+       struct drm_fb_helper helper;
+       struct ast_framebuffer afb;
+       struct list_head fbdev_list;
+       void *sysram;
+       int size;
+       struct ttm_bo_kmap_obj mapping;
+};
+
+#define to_ast_crtc(x) container_of(x, struct ast_crtc, base)
+#define to_ast_connector(x) container_of(x, struct ast_connector, base)
+#define to_ast_encoder(x) container_of(x, struct ast_encoder, base)
+#define to_ast_framebuffer(x) container_of(x, struct ast_framebuffer, base)
+
+struct ast_vbios_stdtable {
+       u8 misc;
+       u8 seq[4];
+       u8 crtc[25];
+       u8 ar[20];
+       u8 gr[9];
+};
+
+struct ast_vbios_enhtable {
+       u32 ht;
+       u32 hde;
+       u32 hfp;
+       u32 hsync;
+       u32 vt;
+       u32 vde;
+       u32 vfp;
+       u32 vsync;
+       u32 dclk_index;
+       u32 flags;
+       u32 refresh_rate;
+       u32 refresh_rate_index;
+       u32 mode_id;
+};
+
+struct ast_vbios_dclk_info {
+       u8 param1;
+       u8 param2;
+       u8 param3;
+};
+
+struct ast_vbios_mode_info {
+       struct ast_vbios_stdtable *std_table;
+       struct ast_vbios_enhtable *enh_table;
+};
+
+extern int ast_mode_init(struct drm_device *dev);
+extern void ast_mode_fini(struct drm_device *dev);
+
+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 ast_fbdev_init(struct drm_device *dev);
+void ast_fbdev_fini(struct drm_device *dev);
+void ast_fbdev_set_suspend(struct drm_device *dev, int state);
+
+struct ast_bo {
+       struct ttm_buffer_object bo;
+       struct ttm_placement placement;
+       struct ttm_bo_kmap_obj kmap;
+       struct drm_gem_object gem;
+       u32 placements[3];
+       int pin_count;
+};
+#define gem_to_ast_bo(gobj) container_of((gobj), struct ast_bo, gem)
+
+static inline struct ast_bo *
+ast_bo(struct ttm_buffer_object *bo)
+{
+       return container_of(bo, struct ast_bo, bo);
+}
+
+
+#define to_ast_obj(x) container_of(x, struct ast_gem_object, base)
+
+#define AST_MM_ALIGN_SHIFT 4
+#define AST_MM_ALIGN_MASK ((1 << AST_MM_ALIGN_SHIFT) - 1)
+
+extern int ast_dumb_create(struct drm_file *file,
+                          struct drm_device *dev,
+                          struct drm_mode_create_dumb *args);
+extern int ast_dumb_destroy(struct drm_file *file,
+                           struct drm_device *dev,
+                           uint32_t handle);
+
+extern int ast_gem_init_object(struct drm_gem_object *obj);
+extern void ast_gem_free_object(struct drm_gem_object *obj);
+extern int ast_dumb_mmap_offset(struct drm_file *file,
+                               struct drm_device *dev,
+                               uint32_t handle,
+                               uint64_t *offset);
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+int ast_mm_init(struct ast_private *ast);
+void ast_mm_fini(struct ast_private *ast);
+
+int ast_bo_create(struct drm_device *dev, int size, int align,
+                 uint32_t flags, struct ast_bo **pastbo);
+
+int ast_gem_create(struct drm_device *dev,
+                  u32 size, bool iskernel,
+                  struct drm_gem_object **obj);
+
+int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr);
+int ast_bo_unpin(struct ast_bo *bo);
+
+int ast_bo_reserve(struct ast_bo *bo, bool no_wait);
+void ast_bo_unreserve(struct ast_bo *bo);
+void ast_ttm_placement(struct ast_bo *bo, int domain);
+int ast_bo_push_sysram(struct ast_bo *bo);
+int ast_mmap(struct file *filp, struct vm_area_struct *vma);
+
+/* ast post */
+void ast_post_gpu(struct drm_device *dev);
+#endif
 
--- /dev/null
+/*
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/tty.h>
+#include <linux/sysrq.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+
+
+#include "drmP.h"
+#include "drm.h"
+#include "drm_crtc.h"
+#include "drm_fb_helper.h"
+#include "ast_drv.h"
+
+static void ast_dirty_update(struct ast_fbdev *afbdev,
+                            int x, int y, int width, int height)
+{
+       int i;
+       struct drm_gem_object *obj;
+       struct ast_bo *bo;
+       int src_offset, dst_offset;
+       int bpp = (afbdev->afb.base.bits_per_pixel + 7)/8;
+       int ret;
+       bool unmap = false;
+
+       obj = afbdev->afb.obj;
+       bo = gem_to_ast_bo(obj);
+
+       ret = ast_bo_reserve(bo, true);
+       if (ret) {
+               DRM_ERROR("failed to reserve fb bo\n");
+               return;
+       }
+
+       if (!bo->kmap.virtual) {
+               ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+               if (ret) {
+                       DRM_ERROR("failed to kmap fb updates\n");
+                       ast_bo_unreserve(bo);
+                       return;
+               }
+               unmap = true;
+       }
+       for (i = y; i < y + height; i++) {
+               /* assume equal stride for now */
+               src_offset = dst_offset = i * afbdev->afb.base.pitches[0] + (x * bpp);
+               memcpy_toio(bo->kmap.virtual + src_offset, afbdev->sysram + src_offset, width * bpp);
+
+       }
+       if (unmap)
+               ttm_bo_kunmap(&bo->kmap);
+
+       ast_bo_unreserve(bo);
+}
+
+static void ast_fillrect(struct fb_info *info,
+                        const struct fb_fillrect *rect)
+{
+       struct ast_fbdev *afbdev = info->par;
+       sys_fillrect(info, rect);
+       ast_dirty_update(afbdev, rect->dx, rect->dy, rect->width,
+                        rect->height);
+}
+
+static void ast_copyarea(struct fb_info *info,
+                        const struct fb_copyarea *area)
+{
+       struct ast_fbdev *afbdev = info->par;
+       sys_copyarea(info, area);
+       ast_dirty_update(afbdev, area->dx, area->dy, area->width,
+                        area->height);
+}
+
+static void ast_imageblit(struct fb_info *info,
+                         const struct fb_image *image)
+{
+       struct ast_fbdev *afbdev = info->par;
+       sys_imageblit(info, image);
+       ast_dirty_update(afbdev, image->dx, image->dy, image->width,
+                        image->height);
+}
+
+static struct fb_ops astfb_ops = {
+       .owner = THIS_MODULE,
+       .fb_check_var = drm_fb_helper_check_var,
+       .fb_set_par = drm_fb_helper_set_par,
+       .fb_fillrect = ast_fillrect,
+       .fb_copyarea = ast_copyarea,
+       .fb_imageblit = ast_imageblit,
+       .fb_pan_display = drm_fb_helper_pan_display,
+       .fb_blank = drm_fb_helper_blank,
+       .fb_setcmap = drm_fb_helper_setcmap,
+       .fb_debug_enter = drm_fb_helper_debug_enter,
+       .fb_debug_leave = drm_fb_helper_debug_leave,
+};
+
+static int astfb_create_object(struct ast_fbdev *afbdev,
+                              struct drm_mode_fb_cmd2 *mode_cmd,
+                              struct drm_gem_object **gobj_p)
+{
+       struct drm_device *dev = afbdev->helper.dev;
+       u32 bpp, depth;
+       u32 size;
+       struct drm_gem_object *gobj;
+
+       int ret = 0;
+       drm_fb_get_bpp_depth(mode_cmd->pixel_format, &depth, &bpp);
+
+       size = mode_cmd->pitches[0] * mode_cmd->height;
+       ret = ast_gem_create(dev, size, true, &gobj);
+       if (ret)
+               return ret;
+
+       *gobj_p = gobj;
+       return ret;
+}
+
+static int astfb_create(struct ast_fbdev *afbdev,
+                       struct drm_fb_helper_surface_size *sizes)
+{
+       struct drm_device *dev = afbdev->helper.dev;
+       struct drm_mode_fb_cmd2 mode_cmd;
+       struct drm_framebuffer *fb;
+       struct fb_info *info;
+       int size, ret;
+       struct device *device = &dev->pdev->dev;
+       void *sysram;
+       struct drm_gem_object *gobj = NULL;
+       struct ast_bo *bo = NULL;
+       mode_cmd.width = sizes->surface_width;
+       mode_cmd.height = sizes->surface_height;
+       mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7)/8);
+
+       mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+                                                         sizes->surface_depth);
+
+       size = mode_cmd.pitches[0] * mode_cmd.height;
+
+       ret = astfb_create_object(afbdev, &mode_cmd, &gobj);
+       if (ret) {
+               DRM_ERROR("failed to create fbcon backing object %d\n", ret);
+               return ret;
+       }
+       bo = gem_to_ast_bo(gobj);
+
+       sysram = vmalloc(size);
+       if (!sysram)
+               return -ENOMEM;
+
+       info = framebuffer_alloc(0, device);
+       if (!info) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       info->par = afbdev;
+
+       ret = ast_framebuffer_init(dev, &afbdev->afb, &mode_cmd, gobj);
+       if (ret)
+               goto out;
+
+       afbdev->sysram = sysram;
+       afbdev->size = size;
+
+       fb = &afbdev->afb.base;
+       afbdev->helper.fb = fb;
+       afbdev->helper.fbdev = info;
+
+       strcpy(info->fix.id, "astdrmfb");
+
+       info->flags = FBINFO_DEFAULT | FBINFO_CAN_FORCE_OUTPUT;
+       info->fbops = &astfb_ops;
+
+       ret = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (ret) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       info->apertures = alloc_apertures(1);
+       if (!info->apertures) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       info->apertures->ranges[0].base = pci_resource_start(dev->pdev, 0);
+       info->apertures->ranges[0].size = pci_resource_len(dev->pdev, 0);
+
+       drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+       drm_fb_helper_fill_var(info, &afbdev->helper, sizes->fb_width, sizes->fb_height);
+
+       info->screen_base = sysram;
+       info->screen_size = size;
+
+       info->pixmap.flags = FB_PIXMAP_SYSTEM;
+
+       DRM_DEBUG_KMS("allocated %dx%d\n",
+                     fb->width, fb->height);
+
+       return 0;
+out:
+       return ret;
+}
+
+static void ast_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+                              u16 blue, int regno)
+{
+       struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+       ast_crtc->lut_r[regno] = red >> 8;
+       ast_crtc->lut_g[regno] = green >> 8;
+       ast_crtc->lut_b[regno] = blue >> 8;
+}
+
+static void ast_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+                              u16 *blue, int regno)
+{
+       struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+       *red = ast_crtc->lut_r[regno] << 8;
+       *green = ast_crtc->lut_g[regno] << 8;
+       *blue = ast_crtc->lut_b[regno] << 8;
+}
+
+static int ast_find_or_create_single(struct drm_fb_helper *helper,
+                                         struct drm_fb_helper_surface_size *sizes)
+{
+       struct ast_fbdev *afbdev = (struct ast_fbdev *)helper;
+       int new_fb = 0;
+       int ret;
+
+       if (!helper->fb) {
+               ret = astfb_create(afbdev, sizes);
+               if (ret)
+                       return ret;
+               new_fb = 1;
+       }
+       return new_fb;
+}
+
+static struct drm_fb_helper_funcs ast_fb_helper_funcs = {
+       .gamma_set = ast_fb_gamma_set,
+       .gamma_get = ast_fb_gamma_get,
+       .fb_probe = ast_find_or_create_single,
+};
+
+static void ast_fbdev_destroy(struct drm_device *dev,
+                             struct ast_fbdev *afbdev)
+{
+       struct fb_info *info;
+       struct ast_framebuffer *afb = &afbdev->afb;
+       if (afbdev->helper.fbdev) {
+               info = afbdev->helper.fbdev;
+               unregister_framebuffer(info);
+               if (info->cmap.len)
+                       fb_dealloc_cmap(&info->cmap);
+               framebuffer_release(info);
+       }
+
+       if (afb->obj) {
+               drm_gem_object_unreference_unlocked(afb->obj);
+               afb->obj = NULL;
+       }
+       drm_fb_helper_fini(&afbdev->helper);
+
+       vfree(afbdev->sysram);
+       drm_framebuffer_cleanup(&afb->base);
+}
+
+int ast_fbdev_init(struct drm_device *dev)
+{
+       struct ast_private *ast = dev->dev_private;
+       struct ast_fbdev *afbdev;
+       int ret;
+
+       afbdev = kzalloc(sizeof(struct ast_fbdev), GFP_KERNEL);
+       if (!afbdev)
+               return -ENOMEM;
+
+       ast->fbdev = afbdev;
+       afbdev->helper.funcs = &ast_fb_helper_funcs;
+       ret = drm_fb_helper_init(dev, &afbdev->helper,
+                                1, 1);
+       if (ret) {
+               kfree(afbdev);
+               return ret;
+       }
+
+       drm_fb_helper_single_add_all_connectors(&afbdev->helper);
+       drm_fb_helper_initial_config(&afbdev->helper, 32);
+       return 0;
+}
+
+void ast_fbdev_fini(struct drm_device *dev)
+{
+       struct ast_private *ast = dev->dev_private;
+
+       if (!ast->fbdev)
+               return;
+
+       ast_fbdev_destroy(dev, ast->fbdev);
+       kfree(ast->fbdev);
+       ast->fbdev = NULL;
+}
+
+void ast_fbdev_set_suspend(struct drm_device *dev, int state)
+{
+       struct ast_private *ast = dev->dev_private;
+
+       if (!ast->fbdev)
+               return;
+
+       fb_set_suspend(ast->fbdev->helper.fbdev, state);
+}
 
--- /dev/null
+/*
+ * 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 "drmP.h"
+#include "ast_drv.h"
+
+
+#include "drm_fb_helper.h"
+#include "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 int ast_user_framebuffer_create_handle(struct drm_framebuffer *fb,
+                                             struct drm_file *file,
+                                             unsigned int *handle)
+{
+       return -EINVAL;
+}
+
+static const struct drm_framebuffer_funcs ast_fb_funcs = {
+       .destroy = ast_user_framebuffer_destroy,
+       .create_handle = ast_user_framebuffer_create_handle,
+};
+
+
+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;
+
+       ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs);
+       if (ret) {
+               DRM_ERROR("framebuffer init failed %d\n", ret);
+               return ret;
+       }
+       drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd);
+       ast_fb->obj = obj;
+       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;
+}
+
+int ast_dumb_destroy(struct drm_file *file,
+                    struct drm_device *dev,
+                    uint32_t handle)
+{
+       return drm_gem_handle_delete(file, handle);
+}
+
+int ast_gem_init_object(struct drm_gem_object *obj)
+{
+       BUG();
+       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 bo->bo.addr_space_offset;
+}
+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;
+
+       mutex_lock(&dev->struct_mutex);
+       obj = drm_gem_object_lookup(dev, file, handle);
+       if (obj == NULL) {
+               ret = -ENOENT;
+               goto out_unlock;
+       }
+
+       bo = gem_to_ast_bo(obj);
+       *offset = ast_bo_mmap_offset(bo);
+
+       drm_gem_object_unreference(obj);
+       ret = 0;
+out_unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+
+}
+
 
--- /dev/null
+/*
+ * Copyright 2012 Red Hat Inc.
+ * Parts based on xf86-video-ast
+ * Copyright (c) 2005 ASPEED Technology 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 <linux/export.h>
+#include "drmP.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "ast_drv.h"
+
+#include "ast_tables.h"
+
+static struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev);
+static void ast_i2c_destroy(struct ast_i2c_chan *i2c);
+static int ast_cursor_set(struct drm_crtc *crtc,
+                         struct drm_file *file_priv,
+                         uint32_t handle,
+                         uint32_t width,
+                         uint32_t height);
+static int ast_cursor_move(struct drm_crtc *crtc,
+                          int x, int y);
+
+static inline void ast_load_palette_index(struct ast_private *ast,
+                                    u8 index, u8 red, u8 green,
+                                    u8 blue)
+{
+       ast_io_write8(ast, AST_IO_DAC_INDEX_WRITE, index);
+       ast_io_read8(ast, AST_IO_SEQ_PORT);
+       ast_io_write8(ast, AST_IO_DAC_DATA, red);
+       ast_io_read8(ast, AST_IO_SEQ_PORT);
+       ast_io_write8(ast, AST_IO_DAC_DATA, green);
+       ast_io_read8(ast, AST_IO_SEQ_PORT);
+       ast_io_write8(ast, AST_IO_DAC_DATA, blue);
+       ast_io_read8(ast, AST_IO_SEQ_PORT);
+}
+
+static void ast_crtc_load_lut(struct drm_crtc *crtc)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+       struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+       int i;
+
+       if (!crtc->enabled)
+               return;
+
+       for (i = 0; i < 256; i++)
+               ast_load_palette_index(ast, i, ast_crtc->lut_r[i],
+                                      ast_crtc->lut_g[i], ast_crtc->lut_b[i]);
+}
+
+static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                                   struct drm_display_mode *adjusted_mode,
+                                   struct ast_vbios_mode_info *vbios_mode)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+       u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate;
+       u32 hborder, vborder;
+
+       switch (crtc->fb->bits_per_pixel) {
+       case 8:
+               vbios_mode->std_table = &vbios_stdtable[VGAModeIndex];
+               color_index = VGAModeIndex - 1;
+               break;
+       case 16:
+               vbios_mode->std_table = &vbios_stdtable[HiCModeIndex];
+               color_index = HiCModeIndex;
+               break;
+       case 24:
+       case 32:
+               vbios_mode->std_table = &vbios_stdtable[TrueCModeIndex];
+               color_index = TrueCModeIndex;
+               break;
+       default:
+               return false;
+       }
+
+       switch (crtc->mode.crtc_hdisplay) {
+       case 640:
+               vbios_mode->enh_table = &res_640x480[refresh_rate_index];
+               break;
+       case 800:
+               vbios_mode->enh_table = &res_800x600[refresh_rate_index];
+               break;
+       case 1024:
+               vbios_mode->enh_table = &res_1024x768[refresh_rate_index];
+               break;
+       case 1280:
+               if (crtc->mode.crtc_vdisplay == 800)
+                       vbios_mode->enh_table = &res_1280x800[refresh_rate_index];
+               else
+                       vbios_mode->enh_table = &res_1280x1024[refresh_rate_index];
+               break;
+       case 1440:
+               vbios_mode->enh_table = &res_1440x900[refresh_rate_index];
+               break;
+       case 1600:
+               vbios_mode->enh_table = &res_1600x1200[refresh_rate_index];
+               break;
+       case 1680:
+               vbios_mode->enh_table = &res_1680x1050[refresh_rate_index];
+               break;
+       case 1920:
+               if (crtc->mode.crtc_vdisplay == 1080)
+                       vbios_mode->enh_table = &res_1920x1080[refresh_rate_index];
+               else
+                       vbios_mode->enh_table = &res_1920x1200[refresh_rate_index];
+               break;
+       default:
+               return false;
+       }
+
+       refresh_rate = drm_mode_vrefresh(mode);
+       while (vbios_mode->enh_table->refresh_rate < refresh_rate) {
+               vbios_mode->enh_table++;
+               if ((vbios_mode->enh_table->refresh_rate > refresh_rate) ||
+                   (vbios_mode->enh_table->refresh_rate == 0xff)) {
+                       vbios_mode->enh_table--;
+                       break;
+               }
+       }
+
+       hborder = (vbios_mode->enh_table->flags & HBorder) ? 8 : 0;
+       vborder = (vbios_mode->enh_table->flags & VBorder) ? 8 : 0;
+
+       adjusted_mode->crtc_htotal = vbios_mode->enh_table->ht;
+       adjusted_mode->crtc_hblank_start = vbios_mode->enh_table->hde + hborder;
+       adjusted_mode->crtc_hblank_end = vbios_mode->enh_table->ht - hborder;
+       adjusted_mode->crtc_hsync_start = vbios_mode->enh_table->hde + hborder +
+               vbios_mode->enh_table->hfp;
+       adjusted_mode->crtc_hsync_end = (vbios_mode->enh_table->hde + hborder +
+                                        vbios_mode->enh_table->hfp +
+                                        vbios_mode->enh_table->hsync);
+
+       adjusted_mode->crtc_vtotal = vbios_mode->enh_table->vt;
+       adjusted_mode->crtc_vblank_start = vbios_mode->enh_table->vde + vborder;
+       adjusted_mode->crtc_vblank_end = vbios_mode->enh_table->vt - vborder;
+       adjusted_mode->crtc_vsync_start = vbios_mode->enh_table->vde + vborder +
+               vbios_mode->enh_table->vfp;
+       adjusted_mode->crtc_vsync_end = (vbios_mode->enh_table->vde + vborder +
+                                        vbios_mode->enh_table->vfp +
+                                        vbios_mode->enh_table->vsync);
+
+       refresh_rate_index = vbios_mode->enh_table->refresh_rate_index;
+       mode_id = vbios_mode->enh_table->mode_id;
+
+       if (ast->chip == AST1180) {
+               /* TODO 1180 */
+       } else {
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8c, (u8)((color_index & 0xf) << 4));
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8d, refresh_rate_index & 0xff);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff);
+
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
+
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x96, adjusted_mode->crtc_vdisplay);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x97, adjusted_mode->crtc_vdisplay >> 8);
+       }
+
+       return true;
+
+
+}
+static void ast_set_std_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                           struct ast_vbios_mode_info *vbios_mode)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+       struct ast_vbios_stdtable *stdtable;
+       u32 i;
+       u8 jreg;
+
+       stdtable = vbios_mode->std_table;
+
+       jreg = stdtable->misc;
+       ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg);
+
+       /* Set SEQ */
+       ast_set_index_reg(ast, AST_IO_SEQ_PORT, 0x00, 0x03);
+       for (i = 0; i < 4; i++) {
+               jreg = stdtable->seq[i];
+               if (!i)
+                       jreg |= 0x20;
+               ast_set_index_reg(ast, AST_IO_SEQ_PORT, (i + 1) , jreg);
+       }
+
+       /* Set CRTC */
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x00);
+       for (i = 0; i < 25; i++)
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, stdtable->crtc[i]);
+
+       /* set AR */
+       jreg = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ);
+       for (i = 0; i < 20; i++) {
+               jreg = stdtable->ar[i];
+               ast_io_write8(ast, AST_IO_AR_PORT_WRITE, (u8)i);
+               ast_io_write8(ast, AST_IO_AR_PORT_WRITE, jreg);
+       }
+       ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x14);
+       ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x00);
+
+       jreg = ast_io_read8(ast, AST_IO_INPUT_STATUS1_READ);
+       ast_io_write8(ast, AST_IO_AR_PORT_WRITE, 0x20);
+
+       /* Set GR */
+       for (i = 0; i < 9; i++)
+               ast_set_index_reg(ast, AST_IO_GR_PORT, i, stdtable->gr[i]);
+}
+
+static void ast_set_crtc_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                            struct ast_vbios_mode_info *vbios_mode)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+       u8 jreg05 = 0, jreg07 = 0, jreg09 = 0, jregAC = 0, jregAD = 0, jregAE = 0;
+       u16 temp;
+
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x00);
+
+       temp = (mode->crtc_htotal >> 3) - 5;
+       if (temp & 0x100)
+               jregAC |= 0x01; /* HT D[8] */
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x00, 0x00, temp);
+
+       temp = (mode->crtc_hdisplay >> 3) - 1;
+       if (temp & 0x100)
+               jregAC |= 0x04; /* HDE D[8] */
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x01, 0x00, temp);
+
+       temp = (mode->crtc_hblank_start >> 3) - 1;
+       if (temp & 0x100)
+               jregAC |= 0x10; /* HBS D[8] */
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x02, 0x00, temp);
+
+       temp = ((mode->crtc_hblank_end >> 3) - 1) & 0x7f;
+       if (temp & 0x20)
+               jreg05 |= 0x80;  /* HBE D[5] */
+       if (temp & 0x40)
+               jregAD |= 0x01;  /* HBE D[5] */
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x03, 0xE0, (temp & 0x1f));
+
+       temp = (mode->crtc_hsync_start >> 3) - 1;
+       if (temp & 0x100)
+               jregAC |= 0x40; /* HRS D[5] */
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x04, 0x00, temp);
+
+       temp = ((mode->crtc_hsync_end >> 3) - 1) & 0x3f;
+       if (temp & 0x20)
+               jregAD |= 0x04; /* HRE D[5] */
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x05, 0x60, (u8)((temp & 0x1f) | jreg05));
+
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAC, 0x00, jregAC);
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAD, 0x00, jregAD);
+
+       /* vert timings */
+       temp = (mode->crtc_vtotal) - 2;
+       if (temp & 0x100)
+               jreg07 |= 0x01;
+       if (temp & 0x200)
+               jreg07 |= 0x20;
+       if (temp & 0x400)
+               jregAE |= 0x01;
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x06, 0x00, temp);
+
+       temp = (mode->crtc_vsync_start) - 1;
+       if (temp & 0x100)
+               jreg07 |= 0x04;
+       if (temp & 0x200)
+               jreg07 |= 0x80;
+       if (temp & 0x400)
+               jregAE |= 0x08;
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x10, 0x00, temp);
+
+       temp = (mode->crtc_vsync_end - 1) & 0x3f;
+       if (temp & 0x10)
+               jregAE |= 0x20;
+       if (temp & 0x20)
+               jregAE |= 0x40;
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x70, temp & 0xf);
+
+       temp = mode->crtc_vdisplay - 1;
+       if (temp & 0x100)
+               jreg07 |= 0x02;
+       if (temp & 0x200)
+               jreg07 |= 0x40;
+       if (temp & 0x400)
+               jregAE |= 0x02;
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x12, 0x00, temp);
+
+       temp = mode->crtc_vblank_start - 1;
+       if (temp & 0x100)
+               jreg07 |= 0x08;
+       if (temp & 0x200)
+               jreg09 |= 0x20;
+       if (temp & 0x400)
+               jregAE |= 0x04;
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x15, 0x00, temp);
+
+       temp = mode->crtc_vblank_end - 1;
+       if (temp & 0x100)
+               jregAE |= 0x10;
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x16, 0x00, temp);
+
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x07, 0x00, jreg07);
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x09, 0xdf, jreg09);
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xAE, 0x00, (jregAE | 0x80));
+
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x11, 0x7f, 0x80);
+}
+
+static void ast_set_offset_reg(struct drm_crtc *crtc)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+
+       u16 offset;
+
+       offset = crtc->fb->pitches[0] >> 3;
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff));
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f);
+}
+
+static void ast_set_dclk_reg(struct drm_device *dev, struct drm_display_mode *mode,
+                            struct ast_vbios_mode_info *vbios_mode)
+{
+       struct ast_private *ast = dev->dev_private;
+       struct ast_vbios_dclk_info *clk_info;
+
+       clk_info = &dclk_table[vbios_mode->enh_table->dclk_index];
+
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xc0, 0x00, clk_info->param1);
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xc1, 0x00, clk_info->param2);
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xbb, 0x0f,
+                              (clk_info->param3 & 0x80) | ((clk_info->param3 & 0x3) << 4));
+}
+
+static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                            struct ast_vbios_mode_info *vbios_mode)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+       u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
+
+       switch (crtc->fb->bits_per_pixel) {
+       case 8:
+               jregA0 = 0x70;
+               jregA3 = 0x01;
+               jregA8 = 0x00;
+               break;
+       case 15:
+       case 16:
+               jregA0 = 0x70;
+               jregA3 = 0x04;
+               jregA8 = 0x02;
+               break;
+       case 32:
+               jregA0 = 0x70;
+               jregA3 = 0x08;
+               jregA8 = 0x02;
+               break;
+       }
+
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa0, 0x8f, jregA0);
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xf0, jregA3);
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa8, 0xfd, jregA8);
+
+       /* Set Threshold */
+       if (ast->chip == AST2300) {
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60);
+       } else if (ast->chip == AST2100 ||
+                  ast->chip == AST1100 ||
+                  ast->chip == AST2200 ||
+                  ast->chip == AST2150) {
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x3f);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x2f);
+       } else {
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x2f);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x1f);
+       }
+}
+
+void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mode,
+                     struct ast_vbios_mode_info *vbios_mode)
+{
+       struct ast_private *ast = dev->dev_private;
+       u8 jreg;
+
+       jreg = ast_io_read8(ast, AST_IO_MISC_PORT_READ);
+       jreg |= (vbios_mode->enh_table->flags & SyncNN);
+       ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg);
+}
+
+bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                    struct ast_vbios_mode_info *vbios_mode)
+{
+       switch (crtc->fb->bits_per_pixel) {
+       case 8:
+               break;
+       default:
+               return false;
+       }
+       return true;
+}
+
+void ast_set_start_address_crt1(struct drm_crtc *crtc, unsigned offset)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+       u32 addr;
+
+       addr = offset >> 2;
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x0d, (u8)(addr & 0xff));
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x0c, (u8)((addr >> 8) & 0xff));
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xaf, (u8)((addr >> 16) & 0xff));
+
+}
+
+static void ast_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+
+       if (ast->chip == AST1180)
+               return;
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+               ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0);
+               ast_crtc_load_lut(crtc);
+               break;
+       case DRM_MODE_DPMS_OFF:
+               ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0x20);
+               break;
+       }
+}
+
+static bool ast_crtc_mode_fixup(struct drm_crtc *crtc,
+                                 struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+/* ast is different - we will force move buffers out of VRAM */
+static int ast_crtc_do_set_base(struct drm_crtc *crtc,
+                               struct drm_framebuffer *fb,
+                               int x, int y, int atomic)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+       struct drm_gem_object *obj;
+       struct ast_framebuffer *ast_fb;
+       struct ast_bo *bo;
+       int ret;
+       u64 gpu_addr;
+
+       /* push the previous fb to system ram */
+       if (!atomic && fb) {
+               ast_fb = to_ast_framebuffer(fb);
+               obj = ast_fb->obj;
+               bo = gem_to_ast_bo(obj);
+               ret = ast_bo_reserve(bo, false);
+               if (ret)
+                       return ret;
+               ast_bo_push_sysram(bo);
+               ast_bo_unreserve(bo);
+       }
+
+       ast_fb = to_ast_framebuffer(crtc->fb);
+       obj = ast_fb->obj;
+       bo = gem_to_ast_bo(obj);
+
+       ret = ast_bo_reserve(bo, false);
+       if (ret)
+               return ret;
+
+       ret = ast_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+       if (ret) {
+               ast_bo_unreserve(bo);
+               return ret;
+       }
+
+       if (&ast->fbdev->afb == ast_fb) {
+               /* if pushing console in kmap it */
+               ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
+               if (ret)
+                       DRM_ERROR("failed to kmap fbcon\n");
+       }
+       ast_bo_unreserve(bo);
+
+       ast_set_start_address_crt1(crtc, (u32)gpu_addr);
+
+       return 0;
+}
+
+static int ast_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+                            struct drm_framebuffer *old_fb)
+{
+       return ast_crtc_do_set_base(crtc, old_fb, x, y, 0);
+}
+
+static int ast_crtc_mode_set(struct drm_crtc *crtc,
+                            struct drm_display_mode *mode,
+                            struct drm_display_mode *adjusted_mode,
+                            int x, int y,
+                            struct drm_framebuffer *old_fb)
+{
+       struct drm_device *dev = crtc->dev;
+       struct ast_private *ast = crtc->dev->dev_private;
+       struct ast_vbios_mode_info vbios_mode;
+       bool ret;
+       if (ast->chip == AST1180) {
+               DRM_ERROR("AST 1180 modesetting not supported\n");
+               return -EINVAL;
+       }
+
+       ret = ast_get_vbios_mode_info(crtc, mode, adjusted_mode, &vbios_mode);
+       if (ret == false)
+               return -EINVAL;
+       ast_open_key(ast);
+
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x04);
+
+       ast_set_std_reg(crtc, adjusted_mode, &vbios_mode);
+       ast_set_crtc_reg(crtc, adjusted_mode, &vbios_mode);
+       ast_set_offset_reg(crtc);
+       ast_set_dclk_reg(dev, adjusted_mode, &vbios_mode);
+       ast_set_ext_reg(crtc, adjusted_mode, &vbios_mode);
+       ast_set_sync_reg(dev, adjusted_mode, &vbios_mode);
+       ast_set_dac_reg(crtc, adjusted_mode, &vbios_mode);
+
+       ast_crtc_mode_set_base(crtc, x, y, old_fb);
+
+       return 0;
+}
+
+static void ast_crtc_disable(struct drm_crtc *crtc)
+{
+
+}
+
+static void ast_crtc_prepare(struct drm_crtc *crtc)
+{
+
+}
+
+static void ast_crtc_commit(struct drm_crtc *crtc)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+       ast_set_index_reg_mask(ast, AST_IO_SEQ_PORT, 0x1, 0xdf, 0);
+}
+
+
+static const struct drm_crtc_helper_funcs ast_crtc_helper_funcs = {
+       .dpms = ast_crtc_dpms,
+       .mode_fixup = ast_crtc_mode_fixup,
+       .mode_set = ast_crtc_mode_set,
+       .mode_set_base = ast_crtc_mode_set_base,
+       .disable = ast_crtc_disable,
+       .load_lut = ast_crtc_load_lut,
+       .disable = ast_crtc_disable,
+       .prepare = ast_crtc_prepare,
+       .commit = ast_crtc_commit,
+
+};
+
+static void ast_crtc_reset(struct drm_crtc *crtc)
+{
+
+}
+
+static void ast_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+                                u16 *blue, uint32_t start, uint32_t size)
+{
+       struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+       int end = (start + size > 256) ? 256 : start + size, i;
+
+       /* userspace palettes are always correct as is */
+       for (i = start; i < end; i++) {
+               ast_crtc->lut_r[i] = red[i] >> 8;
+               ast_crtc->lut_g[i] = green[i] >> 8;
+               ast_crtc->lut_b[i] = blue[i] >> 8;
+       }
+       ast_crtc_load_lut(crtc);
+}
+
+
+static void ast_crtc_destroy(struct drm_crtc *crtc)
+{
+       drm_crtc_cleanup(crtc);
+       kfree(crtc);
+}
+
+static const struct drm_crtc_funcs ast_crtc_funcs = {
+       .cursor_set = ast_cursor_set,
+       .cursor_move = ast_cursor_move,
+       .reset = ast_crtc_reset,
+       .set_config = drm_crtc_helper_set_config,
+       .gamma_set = ast_crtc_gamma_set,
+       .destroy = ast_crtc_destroy,
+};
+
+int ast_crtc_init(struct drm_device *dev)
+{
+       struct ast_crtc *crtc;
+       int i;
+
+       crtc = kzalloc(sizeof(struct ast_crtc), GFP_KERNEL);
+       if (!crtc)
+               return -ENOMEM;
+
+       drm_crtc_init(dev, &crtc->base, &ast_crtc_funcs);
+       drm_mode_crtc_set_gamma_size(&crtc->base, 256);
+       drm_crtc_helper_add(&crtc->base, &ast_crtc_helper_funcs);
+
+       for (i = 0; i < 256; i++) {
+               crtc->lut_r[i] = i;
+               crtc->lut_g[i] = i;
+               crtc->lut_b[i] = i;
+       }
+       return 0;
+}
+
+static void ast_encoder_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+       kfree(encoder);
+}
+
+
+static struct drm_encoder *ast_best_single_encoder(struct drm_connector *connector)
+{
+       int enc_id = connector->encoder_ids[0];
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+
+       /* pick the encoder ids */
+       if (enc_id) {
+               obj = drm_mode_object_find(connector->dev, enc_id, DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       return NULL;
+               encoder = obj_to_encoder(obj);
+               return encoder;
+       }
+       return NULL;
+}
+
+
+static const struct drm_encoder_funcs ast_enc_funcs = {
+       .destroy = ast_encoder_destroy,
+};
+
+static void ast_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+
+}
+
+static bool ast_mode_fixup(struct drm_encoder *encoder,
+                          struct drm_display_mode *mode,
+                          struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void ast_encoder_mode_set(struct drm_encoder *encoder,
+                              struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void ast_encoder_prepare(struct drm_encoder *encoder)
+{
+
+}
+
+static void ast_encoder_commit(struct drm_encoder *encoder)
+{
+
+}
+
+
+static const struct drm_encoder_helper_funcs ast_enc_helper_funcs = {
+       .dpms = ast_encoder_dpms,
+       .mode_fixup = ast_mode_fixup,
+       .prepare = ast_encoder_prepare,
+       .commit = ast_encoder_commit,
+       .mode_set = ast_encoder_mode_set,
+};
+
+int ast_encoder_init(struct drm_device *dev)
+{
+       struct ast_encoder *ast_encoder;
+
+       ast_encoder = kzalloc(sizeof(struct ast_encoder), GFP_KERNEL);
+       if (!ast_encoder)
+               return -ENOMEM;
+
+       drm_encoder_init(dev, &ast_encoder->base, &ast_enc_funcs,
+                        DRM_MODE_ENCODER_DAC);
+       drm_encoder_helper_add(&ast_encoder->base, &ast_enc_helper_funcs);
+
+       ast_encoder->base.possible_crtcs = 1;
+       return 0;
+}
+
+static int ast_get_modes(struct drm_connector *connector)
+{
+       struct ast_connector *ast_connector = to_ast_connector(connector);
+       struct edid *edid;
+       int ret;
+
+       edid = drm_get_edid(connector, &ast_connector->i2c->adapter);
+       if (edid) {
+               drm_mode_connector_update_edid_property(&ast_connector->base, edid);
+               ret = drm_add_edid_modes(connector, edid);
+               return ret;
+       } else
+               drm_mode_connector_update_edid_property(&ast_connector->base, NULL);
+       return 0;
+}
+
+static int ast_mode_valid(struct drm_connector *connector,
+                         struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static void ast_connector_destroy(struct drm_connector *connector)
+{
+       struct ast_connector *ast_connector = to_ast_connector(connector);
+       ast_i2c_destroy(ast_connector->i2c);
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+       kfree(connector);
+}
+
+static enum drm_connector_status
+ast_connector_detect(struct drm_connector *connector, bool force)
+{
+       return connector_status_connected;
+}
+
+static const struct drm_connector_helper_funcs ast_connector_helper_funcs = {
+       .mode_valid = ast_mode_valid,
+       .get_modes = ast_get_modes,
+       .best_encoder = ast_best_single_encoder,
+};
+
+static const struct drm_connector_funcs ast_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = ast_connector_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = ast_connector_destroy,
+};
+
+int ast_connector_init(struct drm_device *dev)
+{
+       struct ast_connector *ast_connector;
+       struct drm_connector *connector;
+       struct drm_encoder *encoder;
+
+       ast_connector = kzalloc(sizeof(struct ast_connector), GFP_KERNEL);
+       if (!ast_connector)
+               return -ENOMEM;
+
+       connector = &ast_connector->base;
+       drm_connector_init(dev, connector, &ast_connector_funcs, DRM_MODE_CONNECTOR_VGA);
+
+       drm_connector_helper_add(connector, &ast_connector_helper_funcs);
+
+       connector->interlace_allowed = 0;
+       connector->doublescan_allowed = 0;
+
+       drm_sysfs_connector_add(connector);
+
+       connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+
+       encoder = list_first_entry(&dev->mode_config.encoder_list, struct drm_encoder, head);
+       drm_mode_connector_attach_encoder(connector, encoder);
+
+       ast_connector->i2c = ast_i2c_create(dev);
+       if (!ast_connector->i2c)
+               DRM_ERROR("failed to add ddc bus for connector\n");
+
+       return 0;
+}
+
+/* allocate cursor cache and pin at start of VRAM */
+int ast_cursor_init(struct drm_device *dev)
+{
+       struct ast_private *ast = dev->dev_private;
+       int size;
+       int ret;
+       struct drm_gem_object *obj;
+       struct ast_bo *bo;
+       uint64_t gpu_addr;
+
+       size = (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE) * AST_DEFAULT_HWC_NUM;
+
+       ret = ast_gem_create(dev, size, true, &obj);
+       if (ret)
+               return ret;
+       bo = gem_to_ast_bo(obj);
+       ret = ast_bo_reserve(bo, false);
+       if (unlikely(ret != 0))
+               goto fail;
+
+       ret = ast_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+       ast_bo_unreserve(bo);
+       if (ret)
+               goto fail;
+
+       /* kmap the object */
+       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &ast->cache_kmap);
+       if (ret)
+               goto fail;
+
+       ast->cursor_cache = obj;
+       ast->cursor_cache_gpu_addr = gpu_addr;
+       DRM_ERROR("pinned cursor cache at %llx\n", ast->cursor_cache_gpu_addr);
+       return 0;
+fail:
+       return ret;
+}
+
+void ast_cursor_fini(struct drm_device *dev)
+{
+       struct ast_private *ast = dev->dev_private;
+       ttm_bo_kunmap(&ast->cache_kmap);
+       drm_gem_object_unreference_unlocked(ast->cursor_cache);
+}
+
+int ast_mode_init(struct drm_device *dev)
+{
+       ast_cursor_init(dev);
+       ast_crtc_init(dev);
+       ast_encoder_init(dev);
+       ast_connector_init(dev);
+       return 0;
+}
+
+void ast_mode_fini(struct drm_device *dev)
+{
+       ast_cursor_fini(dev);
+}
+
+static int get_clock(void *i2c_priv)
+{
+       struct ast_i2c_chan *i2c = i2c_priv;
+       struct ast_private *ast = i2c->dev->dev_private;
+       uint32_t val;
+
+       val = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x10) >> 4;
+       return val & 1 ? 1 : 0;
+}
+
+static int get_data(void *i2c_priv)
+{
+       struct ast_i2c_chan *i2c = i2c_priv;
+       struct ast_private *ast = i2c->dev->dev_private;
+       uint32_t val;
+
+       val = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x20) >> 5;
+       return val & 1 ? 1 : 0;
+}
+
+static void set_clock(void *i2c_priv, int clock)
+{
+       struct ast_i2c_chan *i2c = i2c_priv;
+       struct ast_private *ast = i2c->dev->dev_private;
+       int i;
+       u8 ujcrb7, jtemp;
+
+       for (i = 0; i < 0x10000; i++) {
+               ujcrb7 = ((clock & 0x01) ? 0 : 1);
+               ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xfe, ujcrb7);
+               jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x01);
+               if (ujcrb7 == jtemp)
+                       break;
+       }
+}
+
+static void set_data(void *i2c_priv, int data)
+{
+       struct ast_i2c_chan *i2c = i2c_priv;
+       struct ast_private *ast = i2c->dev->dev_private;
+       int i;
+       u8 ujcrb7, jtemp;
+
+       for (i = 0; i < 0x10000; i++) {
+               ujcrb7 = ((data & 0x01) ? 0 : 1) << 2;
+               ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0xfb, ujcrb7);
+               jtemp = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x04);
+               if (ujcrb7 == jtemp)
+                       break;
+       }
+}
+
+static struct ast_i2c_chan *ast_i2c_create(struct drm_device *dev)
+{
+       struct ast_i2c_chan *i2c;
+       int ret;
+
+       i2c = kzalloc(sizeof(struct ast_i2c_chan), GFP_KERNEL);
+       if (!i2c)
+               return NULL;
+
+       i2c->adapter.owner = THIS_MODULE;
+       i2c->adapter.class = I2C_CLASS_DDC;
+       i2c->adapter.dev.parent = &dev->pdev->dev;
+       i2c->dev = dev;
+       i2c_set_adapdata(&i2c->adapter, i2c);
+       snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
+                "AST i2c bit bus");
+       i2c->adapter.algo_data = &i2c->bit;
+
+       i2c->bit.udelay = 20;
+       i2c->bit.timeout = 2;
+       i2c->bit.data = i2c;
+       i2c->bit.setsda = set_data;
+       i2c->bit.setscl = set_clock;
+       i2c->bit.getsda = get_data;
+       i2c->bit.getscl = get_clock;
+       ret = i2c_bit_add_bus(&i2c->adapter);
+       if (ret) {
+               DRM_ERROR("Failed to register bit i2c\n");
+               goto out_free;
+       }
+
+       return i2c;
+out_free:
+       kfree(i2c);
+       return NULL;
+}
+
+static void ast_i2c_destroy(struct ast_i2c_chan *i2c)
+{
+       if (!i2c)
+               return;
+       i2c_del_adapter(&i2c->adapter);
+       kfree(i2c);
+}
+
+void ast_show_cursor(struct drm_crtc *crtc)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+       u8 jreg;
+
+       jreg = 0x2;
+       /* enable ARGB cursor */
+       jreg |= 1;
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg);
+}
+
+void ast_hide_cursor(struct drm_crtc *crtc)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, 0x00);
+}
+
+static u32 copy_cursor_image(u8 *src, u8 *dst, int width, int height)
+{
+       union {
+               u32 ul;
+               u8 b[4];
+       } srcdata32[2], data32;
+       union {
+               u16 us;
+               u8 b[2];
+       } data16;
+       u32 csum = 0;
+       s32 alpha_dst_delta, last_alpha_dst_delta;
+       u8 *srcxor, *dstxor;
+       int i, j;
+       u32 per_pixel_copy, two_pixel_copy;
+
+       alpha_dst_delta = AST_MAX_HWC_WIDTH << 1;
+       last_alpha_dst_delta = alpha_dst_delta - (width << 1);
+
+       srcxor = src;
+       dstxor = (u8 *)dst + last_alpha_dst_delta + (AST_MAX_HWC_HEIGHT - height) * alpha_dst_delta;
+       per_pixel_copy = width & 1;
+       two_pixel_copy = width >> 1;
+
+       for (j = 0; j < height; j++) {
+               for (i = 0; i < two_pixel_copy; i++) {
+                       srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0;
+                       srcdata32[1].ul = *((u32 *)(srcxor + 4)) & 0xf0f0f0f0;
+                       data32.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4);
+                       data32.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4);
+                       data32.b[2] = srcdata32[0].b[1] | (srcdata32[1].b[0] >> 4);
+                       data32.b[3] = srcdata32[0].b[3] | (srcdata32[1].b[2] >> 4);
+
+                       writel(data32.ul, dstxor);
+                       csum += data32.ul;
+
+                       dstxor += 4;
+                       srcxor += 8;
+
+               }
+
+               for (i = 0; i < per_pixel_copy; i++) {
+                       srcdata32[0].ul = *((u32 *)srcxor) & 0xf0f0f0f0;
+                       data16.b[0] = srcdata32[0].b[1] | (srcdata32[0].b[0] >> 4);
+                       data16.b[1] = srcdata32[0].b[3] | (srcdata32[0].b[2] >> 4);
+                       writew(data16.us, dstxor);
+                       csum += (u32)data16.us;
+
+                       dstxor += 2;
+                       srcxor += 4;
+               }
+               dstxor += last_alpha_dst_delta;
+       }
+       return csum;
+}
+
+static int ast_cursor_set(struct drm_crtc *crtc,
+                         struct drm_file *file_priv,
+                         uint32_t handle,
+                         uint32_t width,
+                         uint32_t height)
+{
+       struct ast_private *ast = crtc->dev->dev_private;
+       struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+       struct drm_gem_object *obj;
+       struct ast_bo *bo;
+       uint64_t gpu_addr;
+       u32 csum;
+       int ret;
+       struct ttm_bo_kmap_obj uobj_map;
+       u8 *src, *dst;
+       bool src_isiomem, dst_isiomem;
+       if (!handle) {
+               ast_hide_cursor(crtc);
+               return 0;
+       }
+
+       if (width > AST_MAX_HWC_WIDTH || height > AST_MAX_HWC_HEIGHT)
+               return -EINVAL;
+
+       obj = drm_gem_object_lookup(crtc->dev, file_priv, handle);
+       if (!obj) {
+               DRM_ERROR("Cannot find cursor object %x for crtc\n", handle);
+               return -ENOENT;
+       }
+       bo = gem_to_ast_bo(obj);
+
+       ret = ast_bo_reserve(bo, false);
+       if (ret)
+               goto fail;
+
+       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &uobj_map);
+
+       src = ttm_kmap_obj_virtual(&uobj_map, &src_isiomem);
+       dst = ttm_kmap_obj_virtual(&ast->cache_kmap, &dst_isiomem);
+
+       if (src_isiomem == true)
+               DRM_ERROR("src cursor bo should be in main memory\n");
+       if (dst_isiomem == false)
+               DRM_ERROR("dst bo should be in VRAM\n");
+
+       dst += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor;
+
+       /* do data transfer to cursor cache */
+       csum = copy_cursor_image(src, dst, width, height);
+
+       /* write checksum + signature */
+       ttm_bo_kunmap(&uobj_map);
+       ast_bo_unreserve(bo);
+       {
+               u8 *dst = (u8 *)ast->cache_kmap.virtual + (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE;
+               writel(csum, dst);
+               writel(width, dst + AST_HWC_SIGNATURE_SizeX);
+               writel(height, dst + AST_HWC_SIGNATURE_SizeY);
+               writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTX);
+               writel(0, dst + AST_HWC_SIGNATURE_HOTSPOTY);
+
+               /* set pattern offset */
+               gpu_addr = ast->cursor_cache_gpu_addr;
+               gpu_addr += (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor;
+               gpu_addr >>= 3;
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc8, gpu_addr & 0xff);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc9, (gpu_addr >> 8) & 0xff);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xca, (gpu_addr >> 16) & 0xff);
+       }
+       ast_crtc->cursor_width = width;
+       ast_crtc->cursor_height = height;
+       ast_crtc->offset_x = AST_MAX_HWC_WIDTH - width;
+       ast_crtc->offset_y = AST_MAX_HWC_WIDTH - height;
+
+       ast->next_cursor = (ast->next_cursor + 1) % AST_DEFAULT_HWC_NUM;
+
+       ast_show_cursor(crtc);
+
+       drm_gem_object_unreference_unlocked(obj);
+       return 0;
+fail:
+       drm_gem_object_unreference_unlocked(obj);
+       return ret;
+}
+
+static int ast_cursor_move(struct drm_crtc *crtc,
+                          int x, int y)
+{
+       struct ast_crtc *ast_crtc = to_ast_crtc(crtc);
+       struct ast_private *ast = crtc->dev->dev_private;
+       int x_offset, y_offset;
+       u8 *sig;
+
+       sig = (u8 *)ast->cache_kmap.virtual + (AST_HWC_SIZE + AST_HWC_SIGNATURE_SIZE)*ast->next_cursor + AST_HWC_SIZE;
+       writel(x, sig + AST_HWC_SIGNATURE_X);
+       writel(y, sig + AST_HWC_SIGNATURE_Y);
+
+       x_offset = ast_crtc->offset_x;
+       y_offset = ast_crtc->offset_y;
+       if (x < 0) {
+               x_offset = (-x) + ast_crtc->offset_x;
+               x = 0;
+       }
+
+       if (y < 0) {
+               y_offset = (-y) + ast_crtc->offset_y;
+               y = 0;
+       }
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc2, x_offset);
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc3, y_offset);
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc4, (x & 0xff));
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc5, ((x >> 8) & 0x0f));
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc6, (y & 0xff));
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xc7, ((y >> 8) & 0x07));
+
+       /* dummy write to fire HWC */
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xCB, 0xFF, 0x00);
+
+       return 0;
+}
 
--- /dev/null
+/*
+ * 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 "drmP.h"
+#include "ast_drv.h"
+
+#include "ast_dram_tables.h"
+
+static void ast_init_dram_2300(struct drm_device *dev);
+
+static void
+ast_enable_vga(struct drm_device *dev)
+{
+       struct ast_private *ast = dev->dev_private;
+
+       ast_io_write8(ast, 0x43, 0x01);
+       ast_io_write8(ast, 0x42, 0x01);
+}
+
+#if 0 /* will use later */
+static bool
+ast_is_vga_enabled(struct drm_device *dev)
+{
+       struct ast_private *ast = dev->dev_private;
+       u8 ch;
+
+       if (ast->chip == AST1180) {
+               /* TODO 1180 */
+       } else {
+               ch = ast_io_read8(ast, 0x43);
+               if (ch) {
+                       ast_open_key(ast);
+                       ch = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff);
+                       return ch & 0x04;
+               }
+       }
+       return 0;
+}
+#endif
+
+static const u8 extreginfo[] = { 0x0f, 0x04, 0x1c, 0xff };
+static const u8 extreginfo_ast2300a0[] = { 0x0f, 0x04, 0x1c, 0xff };
+static const u8 extreginfo_ast2300[] = { 0x0f, 0x04, 0x1f, 0xff };
+
+static void
+ast_set_def_ext_reg(struct drm_device *dev)
+{
+       struct ast_private *ast = dev->dev_private;
+       u8 i, index, reg;
+       const u8 *ext_reg_info;
+
+       /* reset scratch */
+       for (i = 0x81; i <= 0x8f; i++)
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, i, 0x00);
+
+       if (ast->chip == AST2300) {
+               if (dev->pdev->revision >= 0x20)
+                       ext_reg_info = extreginfo_ast2300;
+               else
+                       ext_reg_info = extreginfo_ast2300a0;
+       } else
+               ext_reg_info = extreginfo;
+
+       index = 0xa0;
+       while (*ext_reg_info != 0xff) {
+               ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, index, 0x00, *ext_reg_info);
+               index++;
+               ext_reg_info++;
+       }
+
+       /* disable standard IO/MEM decode if secondary */
+       /* ast_set_index_reg-mask(ast, AST_IO_CRTC_PORT, 0xa1, 0xff, 0x3); */
+
+       /* Set Ext. Default */
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0x8c, 0x00, 0x01);
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb7, 0x00, 0x00);
+
+       /* Enable RAMDAC for A1 */
+       reg = 0x04;
+       if (ast->chip == AST2300)
+               reg |= 0x20;
+       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xb6, 0xff, reg);
+}
+
+static inline u32 mindwm(struct ast_private *ast, u32 r)
+{
+       ast_write32(ast, 0xf004, r & 0xffff0000);
+       ast_write32(ast, 0xf000, 0x1);
+
+       return ast_read32(ast, 0x10000 + (r & 0x0000ffff));
+}
+
+static inline void moutdwm(struct ast_private *ast, u32 r, u32 v)
+{
+       ast_write32(ast, 0xf004, r & 0xffff0000);
+       ast_write32(ast, 0xf000, 0x1);
+       ast_write32(ast, 0x10000 + (r & 0x0000ffff), v);
+}
+
+/*
+ * AST2100/2150 DLL CBR Setting
+ */
+#define CBR_SIZE_AST2150            ((16 << 10) - 1)
+#define CBR_PASSNUM_AST2150          5
+#define CBR_THRESHOLD_AST2150        10
+#define CBR_THRESHOLD2_AST2150       10
+#define TIMEOUT_AST2150              5000000
+
+#define CBR_PATNUM_AST2150           8
+
+static const u32 pattern_AST2150[14] = {
+       0xFF00FF00,
+       0xCC33CC33,
+       0xAA55AA55,
+       0xFFFE0001,
+       0x683501FE,
+       0x0F1929B0,
+       0x2D0B4346,
+       0x60767F02,
+       0x6FBE36A6,
+       0x3A253035,
+       0x3019686D,
+       0x41C6167E,
+       0x620152BF,
+       0x20F050E0
+};
+
+static u32 mmctestburst2_ast2150(struct ast_private *ast, u32 datagen)
+{
+       u32 data, timeout;
+
+       moutdwm(ast, 0x1e6e0070, 0x00000000);
+       moutdwm(ast, 0x1e6e0070, 0x00000001 | (datagen << 3));
+       timeout = 0;
+       do {
+               data = mindwm(ast, 0x1e6e0070) & 0x40;
+               if (++timeout > TIMEOUT_AST2150) {
+                       moutdwm(ast, 0x1e6e0070, 0x00000000);
+                       return 0xffffffff;
+               }
+       } while (!data);
+       moutdwm(ast, 0x1e6e0070, 0x00000000);
+       moutdwm(ast, 0x1e6e0070, 0x00000003 | (datagen << 3));
+       timeout = 0;
+       do {
+               data = mindwm(ast, 0x1e6e0070) & 0x40;
+               if (++timeout > TIMEOUT_AST2150) {
+                       moutdwm(ast, 0x1e6e0070, 0x00000000);
+                       return 0xffffffff;
+               }
+       } while (!data);
+       data = (mindwm(ast, 0x1e6e0070) & 0x80) >> 7;
+       moutdwm(ast, 0x1e6e0070, 0x00000000);
+       return data;
+}
+
+#if 0 /* unused in DDX driver - here for completeness */
+static u32 mmctestsingle2_ast2150(struct ast_private *ast, u32 datagen)
+{
+       u32 data, timeout;
+
+       moutdwm(ast, 0x1e6e0070, 0x00000000);
+       moutdwm(ast, 0x1e6e0070, 0x00000005 | (datagen << 3));
+       timeout = 0;
+       do {
+               data = mindwm(ast, 0x1e6e0070) & 0x40;
+               if (++timeout > TIMEOUT_AST2150) {
+                       moutdwm(ast, 0x1e6e0070, 0x00000000);
+                       return 0xffffffff;
+               }
+       } while (!data);
+       data = (mindwm(ast, 0x1e6e0070) & 0x80) >> 7;
+       moutdwm(ast, 0x1e6e0070, 0x00000000);
+       return data;
+}
+#endif
+
+static int cbrtest_ast2150(struct ast_private *ast)
+{
+       int i;
+
+       for (i = 0; i < 8; i++)
+               if (mmctestburst2_ast2150(ast, i))
+                       return 0;
+       return 1;
+}
+
+static int cbrscan_ast2150(struct ast_private *ast, int busw)
+{
+       u32 patcnt, loop;
+
+       for (patcnt = 0; patcnt < CBR_PATNUM_AST2150; patcnt++) {
+               moutdwm(ast, 0x1e6e007c, pattern_AST2150[patcnt]);
+               for (loop = 0; loop < CBR_PASSNUM_AST2150; loop++) {
+                       if (cbrtest_ast2150(ast))
+                               break;
+               }
+               if (loop == CBR_PASSNUM_AST2150)
+                       return 0;
+       }
+       return 1;
+}
+
+
+static void cbrdlli_ast2150(struct ast_private *ast, int busw)
+{
+       u32 dll_min[4], dll_max[4], dlli, data, passcnt;
+
+cbr_start:
+       dll_min[0] = dll_min[1] = dll_min[2] = dll_min[3] = 0xff;
+       dll_max[0] = dll_max[1] = dll_max[2] = dll_max[3] = 0x0;
+       passcnt = 0;
+
+       for (dlli = 0; dlli < 100; dlli++) {
+               moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24));
+               data = cbrscan_ast2150(ast, busw);
+               if (data != 0) {
+                       if (data & 0x1) {
+                               if (dll_min[0] > dlli)
+                                       dll_min[0] = dlli;
+                               if (dll_max[0] < dlli)
+                                       dll_max[0] = dlli;
+                       }
+                       passcnt++;
+               } else if (passcnt >= CBR_THRESHOLD_AST2150)
+                       goto cbr_start;
+       }
+       if (dll_max[0] == 0 || (dll_max[0]-dll_min[0]) < CBR_THRESHOLD_AST2150)
+               goto cbr_start;
+
+       dlli = dll_min[0] + (((dll_max[0] - dll_min[0]) * 7) >> 4);
+       moutdwm(ast, 0x1e6e0068, dlli | (dlli << 8) | (dlli << 16) | (dlli << 24));
+}
+
+
+
+static void ast_init_dram_reg(struct drm_device *dev)
+{
+       struct ast_private *ast = dev->dev_private;
+       u8 j;
+       u32 data, temp, i;
+       const struct ast_dramstruct *dram_reg_info;
+
+       j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
+
+       if ((j & 0x80) == 0) { /* VGA only */
+               if (ast->chip == AST2000) {
+                       dram_reg_info = ast2000_dram_table_data;
+                       ast_write32(ast, 0xf004, 0x1e6e0000);
+                       ast_write32(ast, 0xf000, 0x1);
+                       ast_write32(ast, 0x10100, 0xa8);
+
+                       do {
+                               ;
+                       } while (ast_read32(ast, 0x10100) != 0xa8);
+               } else {/* AST2100/1100 */
+                       if (ast->chip == AST2100 || ast->chip == 2200)
+                               dram_reg_info = ast2100_dram_table_data;
+                       else
+                               dram_reg_info = ast1100_dram_table_data;
+
+                       ast_write32(ast, 0xf004, 0x1e6e0000);
+                       ast_write32(ast, 0xf000, 0x1);
+                       ast_write32(ast, 0x12000, 0x1688A8A8);
+                       do {
+                               ;
+                       } while (ast_read32(ast, 0x12000) != 0x01);
+
+                       ast_write32(ast, 0x10000, 0xfc600309);
+                       do {
+                               ;
+                       } while (ast_read32(ast, 0x10000) != 0x01);
+               }
+
+               while (dram_reg_info->index != 0xffff) {
+                       if (dram_reg_info->index == 0xff00) {/* delay fn */
+                               for (i = 0; i < 15; i++)
+                                       udelay(dram_reg_info->data);
+                       } else if (dram_reg_info->index == 0x4 && ast->chip != AST2000) {
+                               data = dram_reg_info->data;
+                               if (ast->dram_type == AST_DRAM_1Gx16)
+                                       data = 0x00000d89;
+                               else if (ast->dram_type == AST_DRAM_1Gx32)
+                                       data = 0x00000c8d;
+
+                               temp = ast_read32(ast, 0x12070);
+                               temp &= 0xc;
+                               temp <<= 2;
+                               ast_write32(ast, 0x10000 + dram_reg_info->index, data | temp);
+                       } else
+                               ast_write32(ast, 0x10000 + dram_reg_info->index, dram_reg_info->data);
+                       dram_reg_info++;
+               }
+
+               /* AST 2100/2150 DRAM calibration */
+               data = ast_read32(ast, 0x10120);
+               if (data == 0x5061) { /* 266Mhz */
+                       data = ast_read32(ast, 0x10004);
+                       if (data & 0x40)
+                               cbrdlli_ast2150(ast, 16); /* 16 bits */
+                       else
+                               cbrdlli_ast2150(ast, 32); /* 32 bits */
+               }
+
+               switch (ast->chip) {
+               case AST2000:
+                       temp = ast_read32(ast, 0x10140);
+                       ast_write32(ast, 0x10140, temp | 0x40);
+                       break;
+               case AST1100:
+               case AST2100:
+               case AST2200:
+               case AST2150:
+                       temp = ast_read32(ast, 0x1200c);
+                       ast_write32(ast, 0x1200c, temp & 0xfffffffd);
+                       temp = ast_read32(ast, 0x12040);
+                       ast_write32(ast, 0x12040, temp | 0x40);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       /* wait ready */
+       do {
+               j = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
+       } while ((j & 0x40) == 0);
+}
+
+void ast_post_gpu(struct drm_device *dev)
+{
+       u32 reg;
+       struct ast_private *ast = dev->dev_private;
+
+       pci_read_config_dword(ast->dev->pdev, 0x04, ®);
+       reg |= 0x3;
+       pci_write_config_dword(ast->dev->pdev, 0x04, reg);
+
+       ast_enable_vga(dev);
+       ast_open_key(ast);
+       ast_set_def_ext_reg(dev);
+
+       if (ast->chip == AST2300)
+               ast_init_dram_2300(dev);
+       else
+               ast_init_dram_reg(dev);
+}
+
+/* AST 2300 DRAM settings */
+#define AST_DDR3 0
+#define AST_DDR2 1
+
+struct ast2300_dram_param {
+       u32 dram_type;
+       u32 dram_chipid;
+       u32 dram_freq;
+       u32 vram_size;
+       u32 odt;
+       u32 wodt;
+       u32 rodt;
+       u32 dram_config;
+       u32 reg_PERIOD;
+       u32 reg_MADJ;
+       u32 reg_SADJ;
+       u32 reg_MRS;
+       u32 reg_EMRS;
+       u32 reg_AC1;
+       u32 reg_AC2;
+       u32 reg_DQSIC;
+       u32 reg_DRV;
+       u32 reg_IOZ;
+       u32 reg_DQIDLY;
+       u32 reg_FREQ;
+       u32 madj_max;
+       u32 dll2_finetune_step;
+};
+
+/*
+ * DQSI DLL CBR Setting
+ */
+#define CBR_SIZE1            ((4  << 10) - 1)
+#define CBR_SIZE2            ((64 << 10) - 1)
+#define CBR_PASSNUM          5
+#define CBR_PASSNUM2         5
+#define CBR_THRESHOLD        10
+#define CBR_THRESHOLD2       10
+#define TIMEOUT              5000000
+#define CBR_PATNUM           8
+
+static const u32 pattern[8] = {
+       0xFF00FF00,
+       0xCC33CC33,
+       0xAA55AA55,
+       0x88778877,
+       0x92CC4D6E,
+       0x543D3CDE,
+       0xF1E843C7,
+       0x7C61D253
+};
+
+#if 0 /* unused in DDX, included for completeness */
+static int mmc_test_burst(struct ast_private *ast, u32 datagen)
+{
+       u32 data, timeout;
+
+       moutdwm(ast, 0x1e6e0070, 0x00000000);
+       moutdwm(ast, 0x1e6e0070, 0x000000c1 | (datagen << 3));
+       timeout = 0;
+       do {
+               data = mindwm(ast, 0x1e6e0070) & 0x3000;
+               if (data & 0x2000) {
+                       return 0;
+               }
+               if (++timeout > TIMEOUT) {
+                       moutdwm(ast, 0x1e6e0070, 0x00000000);
+                       return 0;
+               }
+       } while (!data);
+       moutdwm(ast, 0x1e6e0070, 0x00000000);
+       return 1;
+}
+#endif
+
+static int mmc_test_burst2(struct ast_private *ast, u32 datagen)
+{
+       u32 data, timeout;
+
+       moutdwm(ast, 0x1e6e0070, 0x00000000);
+       moutdwm(ast, 0x1e6e0070, 0x00000041 | (datagen << 3));
+       timeout = 0;
+       do {
+               data = mindwm(ast, 0x1e6e0070) & 0x1000;
+               if (++timeout > TIMEOUT) {
+                       moutdwm(ast, 0x1e6e0070, 0x0);
+                       return -1;
+               }
+       } while (!data);
+       data = mindwm(ast, 0x1e6e0078);
+       data = (data | (data >> 16)) & 0xffff;
+       moutdwm(ast, 0x1e6e0070, 0x0);
+       return data;
+}
+
+#if 0 /* Unused in DDX here for completeness */
+static int mmc_test_single(struct ast_private *ast, u32 datagen)
+{
+       u32 data, timeout;
+
+       moutdwm(ast, 0x1e6e0070, 0x00000000);
+       moutdwm(ast, 0x1e6e0070, 0x000000c5 | (datagen << 3));
+       timeout = 0;
+       do {
+               data = mindwm(ast, 0x1e6e0070) & 0x3000;
+               if (data & 0x2000)
+                       return 0;
+               if (++timeout > TIMEOUT) {
+                       moutdwm(ast, 0x1e6e0070, 0x0);
+                       return 0;
+               }
+       } while (!data);
+       moutdwm(ast, 0x1e6e0070, 0x0);
+       return 1;
+}
+#endif
+
+static int mmc_test_single2(struct ast_private *ast, u32 datagen)
+{
+       u32 data, timeout;
+
+       moutdwm(ast, 0x1e6e0070, 0x00000000);
+       moutdwm(ast, 0x1e6e0070, 0x00000005 | (datagen << 3));
+       timeout = 0;
+       do {
+               data = mindwm(ast, 0x1e6e0070) & 0x1000;
+               if (++timeout > TIMEOUT) {
+                       moutdwm(ast, 0x1e6e0070, 0x0);
+                       return -1;
+               }
+       } while (!data);
+       data = mindwm(ast, 0x1e6e0078);
+       data = (data | (data >> 16)) & 0xffff;
+       moutdwm(ast, 0x1e6e0070, 0x0);
+       return data;
+}
+
+static int cbr_test(struct ast_private *ast)
+{
+       u32 data;
+       int i;
+       data = mmc_test_single2(ast, 0);
+       if ((data & 0xff) && (data & 0xff00))
+               return 0;
+       for (i = 0; i < 8; i++) {
+               data = mmc_test_burst2(ast, i);
+               if ((data & 0xff) && (data & 0xff00))
+                       return 0;
+       }
+       if (!data)
+               return 3;
+       else if (data & 0xff)
+               return 2;
+       return 1;
+}
+
+static int cbr_scan(struct ast_private *ast)
+{
+       u32 data, data2, patcnt, loop;
+
+       data2 = 3;
+       for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) {
+               moutdwm(ast, 0x1e6e007c, pattern[patcnt]);
+               for (loop = 0; loop < CBR_PASSNUM2; loop++) {
+                       if ((data = cbr_test(ast)) != 0) {
+                               data2 &= data;
+                               if (!data2)
+                                       return 0;
+                               break;
+                       }
+               }
+               if (loop == CBR_PASSNUM2)
+                       return 0;
+       }
+       return data2;
+}
+
+static u32 cbr_test2(struct ast_private *ast)
+{
+       u32 data;
+
+       data = mmc_test_burst2(ast, 0);
+       if (data == 0xffff)
+               return 0;
+       data |= mmc_test_single2(ast, 0);
+       if (data == 0xffff)
+               return 0;
+
+       return ~data & 0xffff;
+}
+
+static u32 cbr_scan2(struct ast_private *ast)
+{
+       u32 data, data2, patcnt, loop;
+
+       data2 = 0xffff;
+       for (patcnt = 0; patcnt < CBR_PATNUM; patcnt++) {
+               moutdwm(ast, 0x1e6e007c, pattern[patcnt]);
+               for (loop = 0; loop < CBR_PASSNUM2; loop++) {
+                       if ((data = cbr_test2(ast)) != 0) {
+                               data2 &= data;
+                               if (!data)
+                                       return 0;
+                               break;
+                       }
+               }
+               if (loop == CBR_PASSNUM2)
+                       return 0;
+       }
+       return data2;
+}
+
+#if 0 /* unused in DDX - added for completeness */
+static void finetuneDQI(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+       u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, passcnt;
+
+       gold_sadj[0] = (mindwm(ast, 0x1E6E0024) >> 16) & 0xffff;
+       gold_sadj[1] = gold_sadj[0] >> 8;
+       gold_sadj[0] = gold_sadj[0] & 0xff;
+       gold_sadj[0] = (gold_sadj[0] + gold_sadj[1]) >> 1;
+       gold_sadj[1] = gold_sadj[0];
+
+       for (cnt = 0; cnt < 16; cnt++) {
+               dllmin[cnt] = 0xff;
+               dllmax[cnt] = 0x0;
+       }
+       passcnt = 0;
+       for (dlli = 0; dlli < 76; dlli++) {
+               moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24));
+               /* Wait DQSI latch phase calibration */
+               moutdwm(ast, 0x1E6E0074, 0x00000010);
+               moutdwm(ast, 0x1E6E0070, 0x00000003);
+               do {
+                       data = mindwm(ast, 0x1E6E0070);
+               } while (!(data & 0x00001000));
+               moutdwm(ast, 0x1E6E0070, 0x00000000);
+
+               moutdwm(ast, 0x1E6E0074, CBR_SIZE1);
+               data = cbr_scan2(ast);
+               if (data != 0) {
+                       mask = 0x00010001;
+                       for (cnt = 0; cnt < 16; cnt++) {
+                               if (data & mask) {
+                                       if (dllmin[cnt] > dlli) {
+                                               dllmin[cnt] = dlli;
+                                       }
+                                       if (dllmax[cnt] < dlli) {
+                                               dllmax[cnt] = dlli;
+                                       }
+                               }
+                               mask <<= 1;
+                       }
+                       passcnt++;
+               } else if (passcnt >= CBR_THRESHOLD) {
+                       break;
+               }
+       }
+       data = 0;
+       for (cnt = 0; cnt < 8; cnt++) {
+               data >>= 3;
+               if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD)) {
+                       dlli = (dllmin[cnt] + dllmax[cnt]) >> 1;
+                       if (gold_sadj[0] >= dlli) {
+                               dlli = (gold_sadj[0] - dlli) >> 1;
+                               if (dlli > 3) {
+                                       dlli = 3;
+                               }
+                       } else {
+                               dlli = (dlli - gold_sadj[0]) >> 1;
+                               if (dlli > 4) {
+                                       dlli = 4;
+                               }
+                               dlli = (8 - dlli) & 0x7;
+                       }
+                       data |= dlli << 21;
+               }
+       }
+       moutdwm(ast, 0x1E6E0080, data);
+
+       data = 0;
+       for (cnt = 8; cnt < 16; cnt++) {
+               data >>= 3;
+               if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD)) {
+                       dlli = (dllmin[cnt] + dllmax[cnt]) >> 1;
+                       if (gold_sadj[1] >= dlli) {
+                               dlli = (gold_sadj[1] - dlli) >> 1;
+                               if (dlli > 3) {
+                                       dlli = 3;
+                               } else {
+                                       dlli = (dlli - 1) & 0x7;
+                               }
+                       } else {
+                               dlli = (dlli - gold_sadj[1]) >> 1;
+                               dlli += 1;
+                               if (dlli > 4) {
+                                       dlli = 4;
+                               }
+                               dlli = (8 - dlli) & 0x7;
+                       }
+                       data |= dlli << 21;
+               }
+       }
+       moutdwm(ast, 0x1E6E0084, data);
+
+} /* finetuneDQI */
+#endif
+
+static void finetuneDQI_L(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+       u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, passcnt;
+
+FINETUNE_START:
+       for (cnt = 0; cnt < 16; cnt++) {
+               dllmin[cnt] = 0xff;
+               dllmax[cnt] = 0x0;
+       }
+       passcnt = 0;
+       for (dlli = 0; dlli < 76; dlli++) {
+               moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24));
+               /* Wait DQSI latch phase calibration */
+               moutdwm(ast, 0x1E6E0074, 0x00000010);
+               moutdwm(ast, 0x1E6E0070, 0x00000003);
+               do {
+                       data = mindwm(ast, 0x1E6E0070);
+               } while (!(data & 0x00001000));
+               moutdwm(ast, 0x1E6E0070, 0x00000000);
+
+               moutdwm(ast, 0x1E6E0074, CBR_SIZE1);
+               data = cbr_scan2(ast);
+               if (data != 0) {
+                       mask = 0x00010001;
+                       for (cnt = 0; cnt < 16; cnt++) {
+                               if (data & mask) {
+                                       if (dllmin[cnt] > dlli) {
+                                               dllmin[cnt] = dlli;
+                                       }
+                                       if (dllmax[cnt] < dlli) {
+                                               dllmax[cnt] = dlli;
+                                       }
+                               }
+                               mask <<= 1;
+                       }
+                       passcnt++;
+               } else if (passcnt >= CBR_THRESHOLD2) {
+                       break;
+               }
+       }
+       gold_sadj[0] = 0x0;
+       passcnt = 0;
+       for (cnt = 0; cnt < 16; cnt++) {
+               if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+                       gold_sadj[0] += dllmin[cnt];
+                       passcnt++;
+               }
+       }
+       if (passcnt != 16) {
+               goto FINETUNE_START;
+       }
+       gold_sadj[0] = gold_sadj[0] >> 4;
+       gold_sadj[1] = gold_sadj[0];
+
+       data = 0;
+       for (cnt = 0; cnt < 8; cnt++) {
+               data >>= 3;
+               if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+                       dlli = dllmin[cnt];
+                       if (gold_sadj[0] >= dlli) {
+                               dlli = ((gold_sadj[0] - dlli) * 19) >> 5;
+                               if (dlli > 3) {
+                                       dlli = 3;
+                               }
+                       } else {
+                               dlli = ((dlli - gold_sadj[0]) * 19) >> 5;
+                               if (dlli > 4) {
+                                       dlli = 4;
+                               }
+                               dlli = (8 - dlli) & 0x7;
+                       }
+                       data |= dlli << 21;
+               }
+       }
+       moutdwm(ast, 0x1E6E0080, data);
+
+       data = 0;
+       for (cnt = 8; cnt < 16; cnt++) {
+               data >>= 3;
+               if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+                       dlli = dllmin[cnt];
+                       if (gold_sadj[1] >= dlli) {
+                               dlli = ((gold_sadj[1] - dlli) * 19) >> 5;
+                               if (dlli > 3) {
+                                       dlli = 3;
+                               } else {
+                                       dlli = (dlli - 1) & 0x7;
+                               }
+                       } else {
+                               dlli = ((dlli - gold_sadj[1]) * 19) >> 5;
+                               dlli += 1;
+                               if (dlli > 4) {
+                                       dlli = 4;
+                               }
+                               dlli = (8 - dlli) & 0x7;
+                       }
+                       data |= dlli << 21;
+               }
+       }
+       moutdwm(ast, 0x1E6E0084, data);
+
+} /* finetuneDQI_L */
+
+static void finetuneDQI_L2(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+       u32 gold_sadj[2], dllmin[16], dllmax[16], dlli, data, cnt, mask, passcnt, data2;
+
+       for (cnt = 0; cnt < 16; cnt++) {
+               dllmin[cnt] = 0xff;
+               dllmax[cnt] = 0x0;
+       }
+       passcnt = 0;
+       for (dlli = 0; dlli < 76; dlli++) {
+               moutdwm(ast, 0x1E6E0068, 0x00001400 | (dlli << 16) | (dlli << 24));
+               /* Wait DQSI latch phase calibration */
+               moutdwm(ast, 0x1E6E0074, 0x00000010);
+               moutdwm(ast, 0x1E6E0070, 0x00000003);
+               do {
+                       data = mindwm(ast, 0x1E6E0070);
+               } while (!(data & 0x00001000));
+               moutdwm(ast, 0x1E6E0070, 0x00000000);
+
+               moutdwm(ast, 0x1E6E0074, CBR_SIZE2);
+               data = cbr_scan2(ast);
+               if (data != 0) {
+                       mask = 0x00010001;
+                       for (cnt = 0; cnt < 16; cnt++) {
+                               if (data & mask) {
+                                       if (dllmin[cnt] > dlli) {
+                                               dllmin[cnt] = dlli;
+                                       }
+                                       if (dllmax[cnt] < dlli) {
+                                               dllmax[cnt] = dlli;
+                                       }
+                               }
+                               mask <<= 1;
+                       }
+                       passcnt++;
+               } else if (passcnt >= CBR_THRESHOLD2) {
+                       break;
+               }
+       }
+       gold_sadj[0] = 0x0;
+       gold_sadj[1] = 0xFF;
+       for (cnt = 0; cnt < 8; cnt++) {
+               if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+                       if (gold_sadj[0] < dllmin[cnt]) {
+                               gold_sadj[0] = dllmin[cnt];
+                       }
+                       if (gold_sadj[1] > dllmax[cnt]) {
+                               gold_sadj[1] = dllmax[cnt];
+                       }
+               }
+       }
+       gold_sadj[0] = (gold_sadj[1] + gold_sadj[0]) >> 1;
+       gold_sadj[1] = mindwm(ast, 0x1E6E0080);
+
+       data = 0;
+       for (cnt = 0; cnt < 8; cnt++) {
+               data >>= 3;
+               data2 = gold_sadj[1] & 0x7;
+               gold_sadj[1] >>= 3;
+               if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+                       dlli = (dllmin[cnt] + dllmax[cnt]) >> 1;
+                       if (gold_sadj[0] >= dlli) {
+                               dlli = (gold_sadj[0] - dlli) >> 1;
+                               if (dlli > 0) {
+                                       dlli = 1;
+                               }
+                               if (data2 != 3) {
+                                       data2 = (data2 + dlli) & 0x7;
+                               }
+                       } else {
+                               dlli = (dlli - gold_sadj[0]) >> 1;
+                               if (dlli > 0) {
+                                       dlli = 1;
+                               }
+                               if (data2 != 4) {
+                                       data2 = (data2 - dlli) & 0x7;
+                               }
+                       }
+               }
+               data |= data2 << 21;
+       }
+       moutdwm(ast, 0x1E6E0080, data);
+
+       gold_sadj[0] = 0x0;
+       gold_sadj[1] = 0xFF;
+       for (cnt = 8; cnt < 16; cnt++) {
+               if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+                       if (gold_sadj[0] < dllmin[cnt]) {
+                               gold_sadj[0] = dllmin[cnt];
+                       }
+                       if (gold_sadj[1] > dllmax[cnt]) {
+                               gold_sadj[1] = dllmax[cnt];
+                       }
+               }
+       }
+       gold_sadj[0] = (gold_sadj[1] + gold_sadj[0]) >> 1;
+       gold_sadj[1] = mindwm(ast, 0x1E6E0084);
+
+       data = 0;
+       for (cnt = 8; cnt < 16; cnt++) {
+               data >>= 3;
+               data2 = gold_sadj[1] & 0x7;
+               gold_sadj[1] >>= 3;
+               if ((dllmax[cnt] > dllmin[cnt]) && ((dllmax[cnt] - dllmin[cnt]) >= CBR_THRESHOLD2)) {
+                       dlli = (dllmin[cnt] + dllmax[cnt]) >> 1;
+                       if (gold_sadj[0] >= dlli) {
+                               dlli = (gold_sadj[0] - dlli) >> 1;
+                               if (dlli > 0) {
+                                       dlli = 1;
+                               }
+                               if (data2 != 3) {
+                                       data2 = (data2 + dlli) & 0x7;
+                               }
+                       } else {
+                               dlli = (dlli - gold_sadj[0]) >> 1;
+                               if (dlli > 0) {
+                                       dlli = 1;
+                               }
+                               if (data2 != 4) {
+                                       data2 = (data2 - dlli) & 0x7;
+                               }
+                       }
+               }
+               data |= data2 << 21;
+       }
+       moutdwm(ast, 0x1E6E0084, data);
+
+} /* finetuneDQI_L2 */
+
+static void cbr_dll2(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+       u32 dllmin[2], dllmax[2], dlli, data, data2, passcnt;
+
+
+       finetuneDQI_L(ast, param);
+       finetuneDQI_L2(ast, param);
+
+CBR_START2:
+       dllmin[0] = dllmin[1] = 0xff;
+       dllmax[0] = dllmax[1] = 0x0;
+       passcnt = 0;
+       for (dlli = 0; dlli < 76; dlli++) {
+               moutdwm(ast, 0x1E6E0068, 0x00001300 | (dlli << 16) | (dlli << 24));
+               /* Wait DQSI latch phase calibration */
+               moutdwm(ast, 0x1E6E0074, 0x00000010);
+               moutdwm(ast, 0x1E6E0070, 0x00000003);
+               do {
+                       data = mindwm(ast, 0x1E6E0070);
+               } while (!(data & 0x00001000));
+               moutdwm(ast, 0x1E6E0070, 0x00000000);
+
+               moutdwm(ast, 0x1E6E0074, CBR_SIZE2);
+               data = cbr_scan(ast);
+               if (data != 0) {
+                       if (data & 0x1) {
+                               if (dllmin[0] > dlli) {
+                                       dllmin[0] = dlli;
+                               }
+                               if (dllmax[0] < dlli) {
+                                       dllmax[0] = dlli;
+                               }
+                       }
+                       if (data & 0x2) {
+                               if (dllmin[1] > dlli) {
+                                       dllmin[1] = dlli;
+                               }
+                               if (dllmax[1] < dlli) {
+                                       dllmax[1] = dlli;
+                               }
+                       }
+                       passcnt++;
+               } else if (passcnt >= CBR_THRESHOLD) {
+                       break;
+               }
+       }
+       if (dllmax[0] == 0 || (dllmax[0]-dllmin[0]) < CBR_THRESHOLD) {
+               goto CBR_START2;
+       }
+       if (dllmax[1] == 0 || (dllmax[1]-dllmin[1]) < CBR_THRESHOLD) {
+               goto CBR_START2;
+       }
+       dlli  = (dllmin[1] + dllmax[1]) >> 1;
+       dlli <<= 8;
+       dlli += (dllmin[0] + dllmax[0]) >> 1;
+       moutdwm(ast, 0x1E6E0068, (mindwm(ast, 0x1E6E0068) & 0xFFFF) | (dlli << 16));
+
+       data  = (mindwm(ast, 0x1E6E0080) >> 24) & 0x1F;
+       data2 = (mindwm(ast, 0x1E6E0018) & 0xff80ffff) | (data << 16);
+       moutdwm(ast, 0x1E6E0018, data2);
+       moutdwm(ast, 0x1E6E0024, 0x8001 | (data << 1) | (param->dll2_finetune_step << 8));
+
+       /* Wait DQSI latch phase calibration */
+       moutdwm(ast, 0x1E6E0074, 0x00000010);
+       moutdwm(ast, 0x1E6E0070, 0x00000003);
+       do {
+               data = mindwm(ast, 0x1E6E0070);
+       } while (!(data & 0x00001000));
+       moutdwm(ast, 0x1E6E0070, 0x00000000);
+       moutdwm(ast, 0x1E6E0070, 0x00000003);
+       do {
+               data = mindwm(ast, 0x1E6E0070);
+       } while (!(data & 0x00001000));
+       moutdwm(ast, 0x1E6E0070, 0x00000000);
+} /* CBRDLL2 */
+
+static void get_ddr3_info(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+       u32 trap, trap_AC2, trap_MRS;
+
+       moutdwm(ast, 0x1E6E2000, 0x1688A8A8);
+
+       /* Ger trap info */
+       trap = (mindwm(ast, 0x1E6E2070) >> 25) & 0x3;
+       trap_AC2  = 0x00020000 + (trap << 16);
+       trap_AC2 |= 0x00300000 + ((trap & 0x2) << 19);
+       trap_MRS  = 0x00000010 + (trap << 4);
+       trap_MRS |= ((trap & 0x2) << 18);
+
+       param->reg_MADJ       = 0x00034C4C;
+       param->reg_SADJ       = 0x00001800;
+       param->reg_DRV        = 0x000000F0;
+       param->reg_PERIOD     = param->dram_freq;
+       param->rodt           = 0;
+
+       switch (param->dram_freq) {
+       case 336:
+               moutdwm(ast, 0x1E6E2020, 0x0190);
+               param->wodt          = 0;
+               param->reg_AC1       = 0x22202725;
+               param->reg_AC2       = 0xAA007613 | trap_AC2;
+               param->reg_DQSIC     = 0x000000BA;
+               param->reg_MRS       = 0x04001400 | trap_MRS;
+               param->reg_EMRS      = 0x00000000;
+               param->reg_IOZ       = 0x00000034;
+               param->reg_DQIDLY    = 0x00000074;
+               param->reg_FREQ      = 0x00004DC0;
+               param->madj_max      = 96;
+               param->dll2_finetune_step = 3;
+               break;
+       default:
+       case 396:
+               moutdwm(ast, 0x1E6E2020, 0x03F1);
+               param->wodt          = 1;
+               param->reg_AC1       = 0x33302825;
+               param->reg_AC2       = 0xCC009617 | trap_AC2;
+               param->reg_DQSIC     = 0x000000E2;
+               param->reg_MRS       = 0x04001600 | trap_MRS;
+               param->reg_EMRS      = 0x00000000;
+               param->reg_IOZ       = 0x00000034;
+               param->reg_DRV       = 0x000000FA;
+               param->reg_DQIDLY    = 0x00000089;
+               param->reg_FREQ      = 0x000050C0;
+               param->madj_max      = 96;
+               param->dll2_finetune_step = 4;
+
+               switch (param->dram_chipid) {
+               default:
+               case AST_DRAM_512Mx16:
+               case AST_DRAM_1Gx16:
+                       param->reg_AC2   = 0xCC009617 | trap_AC2;
+                       break;
+               case AST_DRAM_2Gx16:
+                       param->reg_AC2   = 0xCC009622 | trap_AC2;
+                       break;
+               case AST_DRAM_4Gx16:
+                       param->reg_AC2   = 0xCC00963F | trap_AC2;
+                       break;
+               }
+               break;
+
+       case 408:
+               moutdwm(ast, 0x1E6E2020, 0x01F0);
+               param->wodt          = 1;
+               param->reg_AC1       = 0x33302825;
+               param->reg_AC2       = 0xCC009617 | trap_AC2;
+               param->reg_DQSIC     = 0x000000E2;
+               param->reg_MRS       = 0x04001600 | trap_MRS;
+               param->reg_EMRS      = 0x00000000;
+               param->reg_IOZ       = 0x00000034;
+               param->reg_DRV       = 0x000000FA;
+               param->reg_DQIDLY    = 0x00000089;
+               param->reg_FREQ      = 0x000050C0;
+               param->madj_max      = 96;
+               param->dll2_finetune_step = 4;
+
+               switch (param->dram_chipid) {
+               default:
+               case AST_DRAM_512Mx16:
+               case AST_DRAM_1Gx16:
+                       param->reg_AC2   = 0xCC009617 | trap_AC2;
+                       break;
+               case AST_DRAM_2Gx16:
+                       param->reg_AC2   = 0xCC009622 | trap_AC2;
+                       break;
+               case AST_DRAM_4Gx16:
+                       param->reg_AC2   = 0xCC00963F | trap_AC2;
+                       break;
+               }
+
+               break;
+       case 456:
+               moutdwm(ast, 0x1E6E2020, 0x0230);
+               param->wodt          = 0;
+               param->reg_AC1       = 0x33302926;
+               param->reg_AC2       = 0xCD44961A;
+               param->reg_DQSIC     = 0x000000FC;
+               param->reg_MRS       = 0x00081830;
+               param->reg_EMRS      = 0x00000000;
+               param->reg_IOZ       = 0x00000045;
+               param->reg_DQIDLY    = 0x00000097;
+               param->reg_FREQ      = 0x000052C0;
+               param->madj_max      = 88;
+               param->dll2_finetune_step = 4;
+               break;
+       case 504:
+               moutdwm(ast, 0x1E6E2020, 0x0270);
+               param->wodt          = 1;
+               param->reg_AC1       = 0x33302926;
+               param->reg_AC2       = 0xDE44A61D;
+               param->reg_DQSIC     = 0x00000117;
+               param->reg_MRS       = 0x00081A30;
+               param->reg_EMRS      = 0x00000000;
+               param->reg_IOZ       = 0x070000BB;
+               param->reg_DQIDLY    = 0x000000A0;
+               param->reg_FREQ      = 0x000054C0;
+               param->madj_max      = 79;
+               param->dll2_finetune_step = 4;
+               break;
+       case 528:
+               moutdwm(ast, 0x1E6E2020, 0x0290);
+               param->wodt          = 1;
+               param->rodt          = 1;
+               param->reg_AC1       = 0x33302926;
+               param->reg_AC2       = 0xEF44B61E;
+               param->reg_DQSIC     = 0x00000125;
+               param->reg_MRS       = 0x00081A30;
+               param->reg_EMRS      = 0x00000040;
+               param->reg_DRV       = 0x000000F5;
+               param->reg_IOZ       = 0x00000023;
+               param->reg_DQIDLY    = 0x00000088;
+               param->reg_FREQ      = 0x000055C0;
+               param->madj_max      = 76;
+               param->dll2_finetune_step = 3;
+               break;
+       case 576:
+               moutdwm(ast, 0x1E6E2020, 0x0140);
+               param->reg_MADJ      = 0x00136868;
+               param->reg_SADJ      = 0x00004534;
+               param->wodt          = 1;
+               param->rodt          = 1;
+               param->reg_AC1       = 0x33302A37;
+               param->reg_AC2       = 0xEF56B61E;
+               param->reg_DQSIC     = 0x0000013F;
+               param->reg_MRS       = 0x00101A50;
+               param->reg_EMRS      = 0x00000040;
+               param->reg_DRV       = 0x000000FA;
+               param->reg_IOZ       = 0x00000023;
+               param->reg_DQIDLY    = 0x00000078;
+               param->reg_FREQ      = 0x000057C0;
+               param->madj_max      = 136;
+               param->dll2_finetune_step = 3;
+               break;
+       case 600:
+               moutdwm(ast, 0x1E6E2020, 0x02E1);
+               param->reg_MADJ      = 0x00136868;
+               param->reg_SADJ      = 0x00004534;
+               param->wodt          = 1;
+               param->rodt          = 1;
+               param->reg_AC1       = 0x32302A37;
+               param->reg_AC2       = 0xDF56B61F;
+               param->reg_DQSIC     = 0x0000014D;
+               param->reg_MRS       = 0x00101A50;
+               param->reg_EMRS      = 0x00000004;
+               param->reg_DRV       = 0x000000F5;
+               param->reg_IOZ       = 0x00000023;
+               param->reg_DQIDLY    = 0x00000078;
+               param->reg_FREQ      = 0x000058C0;
+               param->madj_max      = 132;
+               param->dll2_finetune_step = 3;
+               break;
+       case 624:
+               moutdwm(ast, 0x1E6E2020, 0x0160);
+               param->reg_MADJ      = 0x00136868;
+               param->reg_SADJ      = 0x00004534;
+               param->wodt          = 1;
+               param->rodt          = 1;
+               param->reg_AC1       = 0x32302A37;
+               param->reg_AC2       = 0xEF56B621;
+               param->reg_DQSIC     = 0x0000015A;
+               param->reg_MRS       = 0x02101A50;
+               param->reg_EMRS      = 0x00000004;
+               param->reg_DRV       = 0x000000F5;
+               param->reg_IOZ       = 0x00000034;
+               param->reg_DQIDLY    = 0x00000078;
+               param->reg_FREQ      = 0x000059C0;
+               param->madj_max      = 128;
+               param->dll2_finetune_step = 3;
+               break;
+       } /* switch freq */
+
+       switch (param->dram_chipid) {
+       case AST_DRAM_512Mx16:
+               param->dram_config = 0x130;
+               break;
+       default:
+       case AST_DRAM_1Gx16:
+               param->dram_config = 0x131;
+               break;
+       case AST_DRAM_2Gx16:
+               param->dram_config = 0x132;
+               break;
+       case AST_DRAM_4Gx16:
+               param->dram_config = 0x133;
+               break;
+       }; /* switch size */
+
+       switch (param->vram_size) {
+       default:
+       case AST_VIDMEM_SIZE_8M:
+               param->dram_config |= 0x00;
+               break;
+       case AST_VIDMEM_SIZE_16M:
+               param->dram_config |= 0x04;
+               break;
+       case AST_VIDMEM_SIZE_32M:
+               param->dram_config |= 0x08;
+               break;
+       case AST_VIDMEM_SIZE_64M:
+               param->dram_config |= 0x0c;
+               break;
+       }
+
+}
+
+static void ddr3_init(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+       u32 data, data2;
+
+       moutdwm(ast, 0x1E6E0000, 0xFC600309);
+       moutdwm(ast, 0x1E6E0018, 0x00000100);
+       moutdwm(ast, 0x1E6E0024, 0x00000000);
+       moutdwm(ast, 0x1E6E0034, 0x00000000);
+       udelay(10);
+       moutdwm(ast, 0x1E6E0064, param->reg_MADJ);
+       moutdwm(ast, 0x1E6E0068, param->reg_SADJ);
+       udelay(10);
+       moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000);
+       udelay(10);
+
+       moutdwm(ast, 0x1E6E0004, param->dram_config);
+       moutdwm(ast, 0x1E6E0008, 0x90040f);
+       moutdwm(ast, 0x1E6E0010, param->reg_AC1);
+       moutdwm(ast, 0x1E6E0014, param->reg_AC2);
+       moutdwm(ast, 0x1E6E0020, param->reg_DQSIC);
+       moutdwm(ast, 0x1E6E0080, 0x00000000);
+       moutdwm(ast, 0x1E6E0084, 0x00000000);
+       moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY);
+       moutdwm(ast, 0x1E6E0018, 0x4040A170);
+       moutdwm(ast, 0x1E6E0018, 0x20402370);
+       moutdwm(ast, 0x1E6E0038, 0x00000000);
+       moutdwm(ast, 0x1E6E0040, 0xFF444444);
+       moutdwm(ast, 0x1E6E0044, 0x22222222);
+       moutdwm(ast, 0x1E6E0048, 0x22222222);
+       moutdwm(ast, 0x1E6E004C, 0x00000002);
+       moutdwm(ast, 0x1E6E0050, 0x80000000);
+       moutdwm(ast, 0x1E6E0050, 0x00000000);
+       moutdwm(ast, 0x1E6E0054, 0);
+       moutdwm(ast, 0x1E6E0060, param->reg_DRV);
+       moutdwm(ast, 0x1E6E006C, param->reg_IOZ);
+       moutdwm(ast, 0x1E6E0070, 0x00000000);
+       moutdwm(ast, 0x1E6E0074, 0x00000000);
+       moutdwm(ast, 0x1E6E0078, 0x00000000);
+       moutdwm(ast, 0x1E6E007C, 0x00000000);
+       /* Wait MCLK2X lock to MCLK */
+       do {
+               data = mindwm(ast, 0x1E6E001C);
+       } while (!(data & 0x08000000));
+       moutdwm(ast, 0x1E6E0034, 0x00000001);
+       moutdwm(ast, 0x1E6E000C, 0x00005C04);
+       udelay(10);
+       moutdwm(ast, 0x1E6E000C, 0x00000000);
+       moutdwm(ast, 0x1E6E0034, 0x00000000);
+       data = mindwm(ast, 0x1E6E001C);
+       data = (data >> 8) & 0xff;
+       while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) {
+               data2 = (mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4;
+               if ((data2 & 0xff) > param->madj_max) {
+                       break;
+               }
+               moutdwm(ast, 0x1E6E0064, data2);
+               if (data2 & 0x00100000) {
+                       data2 = ((data2 & 0xff) >> 3) + 3;
+               } else {
+                       data2 = ((data2 & 0xff) >> 2) + 5;
+               }
+               data = mindwm(ast, 0x1E6E0068) & 0xffff00ff;
+               data2 += data & 0xff;
+               data = data | (data2 << 8);
+               moutdwm(ast, 0x1E6E0068, data);
+               udelay(10);
+               moutdwm(ast, 0x1E6E0064, mindwm(ast, 0x1E6E0064) | 0xC0000);
+               udelay(10);
+               data = mindwm(ast, 0x1E6E0018) & 0xfffff1ff;
+               moutdwm(ast, 0x1E6E0018, data);
+               data = data | 0x200;
+               moutdwm(ast, 0x1E6E0018, data);
+               do {
+                       data = mindwm(ast, 0x1E6E001C);
+               } while (!(data & 0x08000000));
+
+               moutdwm(ast, 0x1E6E0034, 0x00000001);
+               moutdwm(ast, 0x1E6E000C, 0x00005C04);
+               udelay(10);
+               moutdwm(ast, 0x1E6E000C, 0x00000000);
+               moutdwm(ast, 0x1E6E0034, 0x00000000);
+               data = mindwm(ast, 0x1E6E001C);
+               data = (data >> 8) & 0xff;
+       }
+       data = mindwm(ast, 0x1E6E0018) | 0xC00;
+       moutdwm(ast, 0x1E6E0018, data);
+
+       moutdwm(ast, 0x1E6E0034, 0x00000001);
+       moutdwm(ast, 0x1E6E000C, 0x00000040);
+       udelay(50);
+       /* Mode Register Setting */
+       moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100);
+       moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
+       moutdwm(ast, 0x1E6E0028, 0x00000005);
+       moutdwm(ast, 0x1E6E0028, 0x00000007);
+       moutdwm(ast, 0x1E6E0028, 0x00000003);
+       moutdwm(ast, 0x1E6E0028, 0x00000001);
+       moutdwm(ast, 0x1E6E002C, param->reg_MRS);
+       moutdwm(ast, 0x1E6E000C, 0x00005C08);
+       moutdwm(ast, 0x1E6E0028, 0x00000001);
+
+       moutdwm(ast, 0x1E6E000C, 0x7FFF5C01);
+       data = 0;
+       if (param->wodt) {
+               data = 0x300;
+       }
+       if (param->rodt) {
+               data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3);
+       }
+       moutdwm(ast, 0x1E6E0034, data | 0x3);
+
+       /* Wait DQI delay lock */
+       do {
+               data = mindwm(ast, 0x1E6E0080);
+       } while (!(data & 0x40000000));
+       /* Wait DQSI delay lock */
+       do {
+               data = mindwm(ast, 0x1E6E0020);
+       } while (!(data & 0x00000800));
+       /* Calibrate the DQSI delay */
+       cbr_dll2(ast, param);
+
+       moutdwm(ast, 0x1E6E0120, param->reg_FREQ);
+       /* ECC Memory Initialization */
+#ifdef ECC
+       moutdwm(ast, 0x1E6E007C, 0x00000000);
+       moutdwm(ast, 0x1E6E0070, 0x221);
+       do {
+               data = mindwm(ast, 0x1E6E0070);
+       } while (!(data & 0x00001000));
+       moutdwm(ast, 0x1E6E0070, 0x00000000);
+       moutdwm(ast, 0x1E6E0050, 0x80000000);
+       moutdwm(ast, 0x1E6E0050, 0x00000000);
+#endif
+
+
+}
+
+static void get_ddr2_info(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+       u32 trap, trap_AC2, trap_MRS;
+
+       moutdwm(ast, 0x1E6E2000, 0x1688A8A8);
+
+       /* Ger trap info */
+       trap = (mindwm(ast, 0x1E6E2070) >> 25) & 0x3;
+       trap_AC2  = (trap << 20) | (trap << 16);
+       trap_AC2 += 0x00110000;
+       trap_MRS  = 0x00000040 | (trap << 4);
+
+
+       param->reg_MADJ       = 0x00034C4C;
+       param->reg_SADJ       = 0x00001800;
+       param->reg_DRV        = 0x000000F0;
+       param->reg_PERIOD     = param->dram_freq;
+       param->rodt           = 0;
+
+       switch (param->dram_freq) {
+       case 264:
+               moutdwm(ast, 0x1E6E2020, 0x0130);
+               param->wodt          = 0;
+               param->reg_AC1       = 0x11101513;
+               param->reg_AC2       = 0x78117011;
+               param->reg_DQSIC     = 0x00000092;
+               param->reg_MRS       = 0x00000842;
+               param->reg_EMRS      = 0x00000000;
+               param->reg_DRV       = 0x000000F0;
+               param->reg_IOZ       = 0x00000034;
+               param->reg_DQIDLY    = 0x0000005A;
+               param->reg_FREQ      = 0x00004AC0;
+               param->madj_max      = 138;
+               param->dll2_finetune_step = 3;
+               break;
+       case 336:
+               moutdwm(ast, 0x1E6E2020, 0x0190);
+               param->wodt          = 1;
+               param->reg_AC1       = 0x22202613;
+               param->reg_AC2       = 0xAA009016 | trap_AC2;
+               param->reg_DQSIC     = 0x000000BA;
+               param->reg_MRS       = 0x00000A02 | trap_MRS;
+               param->reg_EMRS      = 0x00000040;
+               param->reg_DRV       = 0x000000FA;
+               param->reg_IOZ       = 0x00000034;
+               param->reg_DQIDLY    = 0x00000074;
+               param->reg_FREQ      = 0x00004DC0;
+               param->madj_max      = 96;
+               param->dll2_finetune_step = 3;
+               break;
+       default:
+       case 396:
+               moutdwm(ast, 0x1E6E2020, 0x03F1);
+               param->wodt          = 1;
+               param->rodt          = 0;
+               param->reg_AC1       = 0x33302714;
+               param->reg_AC2       = 0xCC00B01B | trap_AC2;
+               param->reg_DQSIC     = 0x000000E2;
+               param->reg_MRS       = 0x00000C02 | trap_MRS;
+               param->reg_EMRS      = 0x00000040;
+               param->reg_DRV       = 0x000000FA;
+               param->reg_IOZ       = 0x00000034;
+               param->reg_DQIDLY    = 0x00000089;
+               param->reg_FREQ      = 0x000050C0;
+               param->madj_max      = 96;
+               param->dll2_finetune_step = 4;
+
+               switch (param->dram_chipid) {
+               case AST_DRAM_512Mx16:
+                       param->reg_AC2   = 0xCC00B016 | trap_AC2;
+                       break;
+               default:
+               case AST_DRAM_1Gx16:
+                       param->reg_AC2   = 0xCC00B01B | trap_AC2;
+                       break;
+               case AST_DRAM_2Gx16:
+                       param->reg_AC2   = 0xCC00B02B | trap_AC2;
+                       break;
+               case AST_DRAM_4Gx16:
+                       param->reg_AC2   = 0xCC00B03F | trap_AC2;
+                       break;
+               }
+
+               break;
+
+       case 408:
+               moutdwm(ast, 0x1E6E2020, 0x01F0);
+               param->wodt          = 1;
+               param->rodt          = 0;
+               param->reg_AC1       = 0x33302714;
+               param->reg_AC2       = 0xCC00B01B | trap_AC2;
+               param->reg_DQSIC     = 0x000000E2;
+               param->reg_MRS       = 0x00000C02 | trap_MRS;
+               param->reg_EMRS      = 0x00000040;
+               param->reg_DRV       = 0x000000FA;
+               param->reg_IOZ       = 0x00000034;
+               param->reg_DQIDLY    = 0x00000089;
+               param->reg_FREQ      = 0x000050C0;
+               param->madj_max      = 96;
+               param->dll2_finetune_step = 4;
+
+               switch (param->dram_chipid) {
+               case AST_DRAM_512Mx16:
+                       param->reg_AC2   = 0xCC00B016 | trap_AC2;
+                       break;
+               default:
+               case AST_DRAM_1Gx16:
+                       param->reg_AC2   = 0xCC00B01B | trap_AC2;
+                       break;
+               case AST_DRAM_2Gx16:
+                       param->reg_AC2   = 0xCC00B02B | trap_AC2;
+                       break;
+               case AST_DRAM_4Gx16:
+                       param->reg_AC2   = 0xCC00B03F | trap_AC2;
+                       break;
+               }
+
+               break;
+       case 456:
+               moutdwm(ast, 0x1E6E2020, 0x0230);
+               param->wodt          = 0;
+               param->reg_AC1       = 0x33302815;
+               param->reg_AC2       = 0xCD44B01E;
+               param->reg_DQSIC     = 0x000000FC;
+               param->reg_MRS       = 0x00000E72;
+               param->reg_EMRS      = 0x00000000;
+               param->reg_DRV       = 0x00000000;
+               param->reg_IOZ       = 0x00000034;
+               param->reg_DQIDLY    = 0x00000097;
+               param->reg_FREQ      = 0x000052C0;
+               param->madj_max      = 88;
+               param->dll2_finetune_step = 3;
+               break;
+       case 504:
+               moutdwm(ast, 0x1E6E2020, 0x0261);
+               param->wodt          = 1;
+               param->rodt          = 1;
+               param->reg_AC1       = 0x33302815;
+               param->reg_AC2       = 0xDE44C022;
+               param->reg_DQSIC     = 0x00000117;
+               param->reg_MRS       = 0x00000E72;
+               param->reg_EMRS      = 0x00000040;
+               param->reg_DRV       = 0x0000000A;
+               param->reg_IOZ       = 0x00000045;
+               param->reg_DQIDLY    = 0x000000A0;
+               param->reg_FREQ      = 0x000054C0;
+               param->madj_max      = 79;
+               param->dll2_finetune_step = 3;
+               break;
+       case 528:
+               moutdwm(ast, 0x1E6E2020, 0x0120);
+               param->wodt          = 1;
+               param->rodt          = 1;
+               param->reg_AC1       = 0x33302815;
+               param->reg_AC2       = 0xEF44D024;
+               param->reg_DQSIC     = 0x00000125;
+               param->reg_MRS       = 0x00000E72;
+               param->reg_EMRS      = 0x00000004;
+               param->reg_DRV       = 0x000000F9;
+               param->reg_IOZ       = 0x00000045;
+               param->reg_DQIDLY    = 0x000000A7;
+               param->reg_FREQ      = 0x000055C0;
+               param->madj_max      = 76;
+               param->dll2_finetune_step = 3;
+               break;
+       case 552:
+               moutdwm(ast, 0x1E6E2020, 0x02A1);
+               param->wodt          = 1;
+               param->rodt          = 1;
+               param->reg_AC1       = 0x43402915;
+               param->reg_AC2       = 0xFF44E025;
+               param->reg_DQSIC     = 0x00000132;
+               param->reg_MRS       = 0x00000E72;
+               param->reg_EMRS      = 0x00000040;
+               param->reg_DRV       = 0x0000000A;
+               param->reg_IOZ       = 0x00000045;
+               param->reg_DQIDLY    = 0x000000AD;
+               param->reg_FREQ      = 0x000056C0;
+               param->madj_max      = 76;
+               param->dll2_finetune_step = 3;
+               break;
+       case 576:
+               moutdwm(ast, 0x1E6E2020, 0x0140);
+               param->wodt          = 1;
+               param->rodt          = 1;
+               param->reg_AC1       = 0x43402915;
+               param->reg_AC2       = 0xFF44E027;
+               param->reg_DQSIC     = 0x0000013F;
+               param->reg_MRS       = 0x00000E72;
+               param->reg_EMRS      = 0x00000004;
+               param->reg_DRV       = 0x000000F5;
+               param->reg_IOZ       = 0x00000045;
+               param->reg_DQIDLY    = 0x000000B3;
+               param->reg_FREQ      = 0x000057C0;
+               param->madj_max      = 76;
+               param->dll2_finetune_step = 3;
+               break;
+       }
+
+       switch (param->dram_chipid) {
+       case AST_DRAM_512Mx16:
+               param->dram_config = 0x100;
+               break;
+       default:
+       case AST_DRAM_1Gx16:
+               param->dram_config = 0x121;
+               break;
+       case AST_DRAM_2Gx16:
+               param->dram_config = 0x122;
+               break;
+       case AST_DRAM_4Gx16:
+               param->dram_config = 0x123;
+               break;
+       }; /* switch size */
+
+       switch (param->vram_size) {
+       default:
+       case AST_VIDMEM_SIZE_8M:
+               param->dram_config |= 0x00;
+               break;
+       case AST_VIDMEM_SIZE_16M:
+               param->dram_config |= 0x04;
+               break;
+       case AST_VIDMEM_SIZE_32M:
+               param->dram_config |= 0x08;
+               break;
+       case AST_VIDMEM_SIZE_64M:
+               param->dram_config |= 0x0c;
+               break;
+       }
+}
+
+static void ddr2_init(struct ast_private *ast, struct ast2300_dram_param *param)
+{
+       u32 data, data2;
+
+       moutdwm(ast, 0x1E6E0000, 0xFC600309);
+       moutdwm(ast, 0x1E6E0018, 0x00000100);
+       moutdwm(ast, 0x1E6E0024, 0x00000000);
+       moutdwm(ast, 0x1E6E0064, param->reg_MADJ);
+       moutdwm(ast, 0x1E6E0068, param->reg_SADJ);
+       udelay(10);
+       moutdwm(ast, 0x1E6E0064, param->reg_MADJ | 0xC0000);
+       udelay(10);
+
+       moutdwm(ast, 0x1E6E0004, param->dram_config);
+       moutdwm(ast, 0x1E6E0008, 0x90040f);
+       moutdwm(ast, 0x1E6E0010, param->reg_AC1);
+       moutdwm(ast, 0x1E6E0014, param->reg_AC2);
+       moutdwm(ast, 0x1E6E0020, param->reg_DQSIC);
+       moutdwm(ast, 0x1E6E0080, 0x00000000);
+       moutdwm(ast, 0x1E6E0084, 0x00000000);
+       moutdwm(ast, 0x1E6E0088, param->reg_DQIDLY);
+       moutdwm(ast, 0x1E6E0018, 0x4040A130);
+       moutdwm(ast, 0x1E6E0018, 0x20402330);
+       moutdwm(ast, 0x1E6E0038, 0x00000000);
+       moutdwm(ast, 0x1E6E0040, 0xFF808000);
+       moutdwm(ast, 0x1E6E0044, 0x88848466);
+       moutdwm(ast, 0x1E6E0048, 0x44440008);
+       moutdwm(ast, 0x1E6E004C, 0x00000000);
+       moutdwm(ast, 0x1E6E0050, 0x80000000);
+       moutdwm(ast, 0x1E6E0050, 0x00000000);
+       moutdwm(ast, 0x1E6E0054, 0);
+       moutdwm(ast, 0x1E6E0060, param->reg_DRV);
+       moutdwm(ast, 0x1E6E006C, param->reg_IOZ);
+       moutdwm(ast, 0x1E6E0070, 0x00000000);
+       moutdwm(ast, 0x1E6E0074, 0x00000000);
+       moutdwm(ast, 0x1E6E0078, 0x00000000);
+       moutdwm(ast, 0x1E6E007C, 0x00000000);
+
+       /* Wait MCLK2X lock to MCLK */
+       do {
+               data = mindwm(ast, 0x1E6E001C);
+       } while (!(data & 0x08000000));
+       moutdwm(ast, 0x1E6E0034, 0x00000001);
+       moutdwm(ast, 0x1E6E000C, 0x00005C04);
+       udelay(10);
+       moutdwm(ast, 0x1E6E000C, 0x00000000);
+       moutdwm(ast, 0x1E6E0034, 0x00000000);
+       data = mindwm(ast, 0x1E6E001C);
+       data = (data >> 8) & 0xff;
+       while ((data & 0x08) || ((data & 0x7) < 2) || (data < 4)) {
+               data2 = (mindwm(ast, 0x1E6E0064) & 0xfff3ffff) + 4;
+               if ((data2 & 0xff) > param->madj_max) {
+                       break;
+               }
+               moutdwm(ast, 0x1E6E0064, data2);
+               if (data2 & 0x00100000) {
+                       data2 = ((data2 & 0xff) >> 3) + 3;
+               } else {
+                       data2 = ((data2 & 0xff) >> 2) + 5;
+               }
+               data = mindwm(ast, 0x1E6E0068) & 0xffff00ff;
+               data2 += data & 0xff;
+               data = data | (data2 << 8);
+               moutdwm(ast, 0x1E6E0068, data);
+               udelay(10);
+               moutdwm(ast, 0x1E6E0064, mindwm(ast, 0x1E6E0064) | 0xC0000);
+               udelay(10);
+               data = mindwm(ast, 0x1E6E0018) & 0xfffff1ff;
+               moutdwm(ast, 0x1E6E0018, data);
+               data = data | 0x200;
+               moutdwm(ast, 0x1E6E0018, data);
+               do {
+                       data = mindwm(ast, 0x1E6E001C);
+               } while (!(data & 0x08000000));
+
+               moutdwm(ast, 0x1E6E0034, 0x00000001);
+               moutdwm(ast, 0x1E6E000C, 0x00005C04);
+               udelay(10);
+               moutdwm(ast, 0x1E6E000C, 0x00000000);
+               moutdwm(ast, 0x1E6E0034, 0x00000000);
+               data = mindwm(ast, 0x1E6E001C);
+               data = (data >> 8) & 0xff;
+       }
+       data = mindwm(ast, 0x1E6E0018) | 0xC00;
+       moutdwm(ast, 0x1E6E0018, data);
+
+       moutdwm(ast, 0x1E6E0034, 0x00000001);
+       moutdwm(ast, 0x1E6E000C, 0x00000000);
+       udelay(50);
+       /* Mode Register Setting */
+       moutdwm(ast, 0x1E6E002C, param->reg_MRS | 0x100);
+       moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
+       moutdwm(ast, 0x1E6E0028, 0x00000005);
+       moutdwm(ast, 0x1E6E0028, 0x00000007);
+       moutdwm(ast, 0x1E6E0028, 0x00000003);
+       moutdwm(ast, 0x1E6E0028, 0x00000001);
+
+       moutdwm(ast, 0x1E6E000C, 0x00005C08);
+       moutdwm(ast, 0x1E6E002C, param->reg_MRS);
+       moutdwm(ast, 0x1E6E0028, 0x00000001);
+       moutdwm(ast, 0x1E6E0030, param->reg_EMRS | 0x380);
+       moutdwm(ast, 0x1E6E0028, 0x00000003);
+       moutdwm(ast, 0x1E6E0030, param->reg_EMRS);
+       moutdwm(ast, 0x1E6E0028, 0x00000003);
+
+       moutdwm(ast, 0x1E6E000C, 0x7FFF5C01);
+       data = 0;
+       if (param->wodt) {
+               data = 0x500;
+       }
+       if (param->rodt) {
+               data = data | 0x3000 | ((param->reg_AC2 & 0x60000) >> 3);
+       }
+       moutdwm(ast, 0x1E6E0034, data | 0x3);
+       moutdwm(ast, 0x1E6E0120, param->reg_FREQ);
+
+       /* Wait DQI delay lock */
+       do {
+               data = mindwm(ast, 0x1E6E0080);
+       } while (!(data & 0x40000000));
+       /* Wait DQSI delay lock */
+       do {
+               data = mindwm(ast, 0x1E6E0020);
+       } while (!(data & 0x00000800));
+       /* Calibrate the DQSI delay */
+       cbr_dll2(ast, param);
+
+       /* ECC Memory Initialization */
+#ifdef ECC
+       moutdwm(ast, 0x1E6E007C, 0x00000000);
+       moutdwm(ast, 0x1E6E0070, 0x221);
+       do {
+               data = mindwm(ast, 0x1E6E0070);
+       } while (!(data & 0x00001000));
+       moutdwm(ast, 0x1E6E0070, 0x00000000);
+       moutdwm(ast, 0x1E6E0050, 0x80000000);
+       moutdwm(ast, 0x1E6E0050, 0x00000000);
+#endif
+
+}
+
+static void ast_init_dram_2300(struct drm_device *dev)
+{
+       struct ast_private *ast = dev->dev_private;
+       struct ast2300_dram_param param;
+       u32 temp;
+       u8 reg;
+
+       reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
+       if ((reg & 0x80) == 0) {/* vga only */
+               ast_write32(ast, 0xf004, 0x1e6e0000);
+               ast_write32(ast, 0xf000, 0x1);
+               ast_write32(ast, 0x12000, 0x1688a8a8);
+               do {
+                       ;
+               } while (ast_read32(ast, 0x12000) != 0x1);
+
+               ast_write32(ast, 0x10000, 0xfc600309);
+               do {
+                       ;
+               } while (ast_read32(ast, 0x10000) != 0x1);
+
+               /* Slow down CPU/AHB CLK in VGA only mode */
+               temp = ast_read32(ast, 0x12008);
+               temp |= 0x73;
+               ast_write32(ast, 0x12008, temp);
+
+               param.dram_type = AST_DDR3;
+               if (temp & 0x01000000)
+                       param.dram_type = AST_DDR2;
+               param.dram_chipid = ast->dram_type;
+               param.dram_freq = ast->mclk;
+               param.vram_size = ast->vram_size;
+
+               if (param.dram_type == AST_DDR3) {
+                       get_ddr3_info(ast, ¶m);
+                       ddr3_init(ast, ¶m);
+               } else {
+                       get_ddr2_info(ast, ¶m);
+                       ddr2_init(ast, ¶m);
+               }
+
+               temp = mindwm(ast, 0x1e6e2040);
+               moutdwm(ast, 0x1e6e2040, temp | 0x40);
+       }
+
+       /* wait ready */
+       do {
+               reg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
+       } while ((reg & 0x40) == 0);
+}
+
 
--- /dev/null
+/*
+ * Copyright (c) 2005 ASPEED Technology Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the authors not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  The authors makes no representations
+ * about the suitability of this software for any purpose.  It is provided
+ * "as is" without express or implied warranty.
+ *
+ * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, 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.
+ */
+/* Ported from xf86-video-ast driver */
+
+#ifndef AST_TABLES_H
+#define AST_TABLES_H
+
+/* Std. Table Index Definition */
+#define TextModeIndex          0
+#define EGAModeIndex           1
+#define VGAModeIndex           2
+#define HiCModeIndex           3
+#define TrueCModeIndex         4
+
+#define Charx8Dot               0x00000001
+#define HalfDCLK                0x00000002
+#define DoubleScanMode          0x00000004
+#define LineCompareOff          0x00000008
+#define SyncPP                  0x00000000
+#define SyncPN                  0x00000040
+#define SyncNP                  0x00000080
+#define SyncNN                  0x000000C0
+#define HBorder                 0x00000020
+#define VBorder                 0x00000010
+#define WideScreenMode         0x00000100
+
+
+/* DCLK Index */
+#define VCLK25_175                     0x00
+#define VCLK28_322                     0x01
+#define VCLK31_5                       0x02
+#define VCLK36                         0x03
+#define VCLK40                         0x04
+#define VCLK49_5                       0x05
+#define VCLK50                         0x06
+#define VCLK56_25                      0x07
+#define VCLK65                 0x08
+#define VCLK75                 0x09
+#define VCLK78_75                      0x0A
+#define VCLK94_5                       0x0B
+#define VCLK108                        0x0C
+#define VCLK135                        0x0D
+#define VCLK157_5                      0x0E
+#define VCLK162                        0x0F
+/* #define VCLK193_25                  0x10 */
+#define VCLK154                0x10
+#define VCLK83_5               0x11
+#define VCLK106_5              0x12
+#define VCLK146_25             0x13
+#define VCLK148_5              0x14
+
+static struct ast_vbios_dclk_info dclk_table[] = {
+       {0x2C, 0xE7, 0x03},                                     /* 00: VCLK25_175       */
+       {0x95, 0x62, 0x03},                                     /* 01: VCLK28_322       */
+       {0x67, 0x63, 0x01},                                     /* 02: VCLK31_5         */
+       {0x76, 0x63, 0x01},                                     /* 03: VCLK36           */
+       {0xEE, 0x67, 0x01},                                     /* 04: VCLK40           */
+       {0x82, 0x62, 0x01},                             /* 05: VCLK49_5         */
+       {0xC6, 0x64, 0x01},                                     /* 06: VCLK50           */
+       {0x94, 0x62, 0x01},                                     /* 07: VCLK56_25        */
+       {0x80, 0x64, 0x00},                                     /* 08: VCLK65           */
+       {0x7B, 0x63, 0x00},                                     /* 09: VCLK75           */
+       {0x67, 0x62, 0x00},                                     /* 0A: VCLK78_75        */
+       {0x7C, 0x62, 0x00},                                     /* 0B: VCLK94_5         */
+       {0x8E, 0x62, 0x00},                                     /* 0C: VCLK108          */
+       {0x85, 0x24, 0x00},                                     /* 0D: VCLK135          */
+       {0x67, 0x22, 0x00},                                     /* 0E: VCLK157_5        */
+       {0x6A, 0x22, 0x00},                                     /* 0F: VCLK162          */
+       {0x4d, 0x4c, 0x80},                                     /* 10: VCLK154          */
+       {0xa7, 0x78, 0x80},                                     /* 11: VCLK83.5         */
+       {0x28, 0x49, 0x80},                                     /* 12: VCLK106.5        */
+       {0x37, 0x49, 0x80},                                     /* 13: VCLK146.25       */
+       {0x1f, 0x45, 0x80},                                     /* 14: VCLK148.5        */
+};
+
+static struct ast_vbios_stdtable vbios_stdtable[] = {
+       /* MD_2_3_400 */
+       {
+               0x67,
+               {0x00,0x03,0x00,0x02},
+               {0x5f,0x4f,0x50,0x82,0x55,0x81,0xbf,0x1f,
+                0x00,0x4f,0x0d,0x0e,0x00,0x00,0x00,0x00,
+                0x9c,0x8e,0x8f,0x28,0x1f,0x96,0xb9,0xa3,
+                0xff},
+               {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+                0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+                0x0c,0x00,0x0f,0x08},
+               {0x00,0x00,0x00,0x00,0x00,0x10,0x0e,0x00,
+                0xff}
+       },
+       /* Mode12/ExtEGATable */
+       {
+               0xe3,
+               {0x01,0x0f,0x00,0x06},
+               {0x5f,0x4f,0x50,0x82,0x55,0x81,0x0b,0x3e,
+                0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+                0xe9,0x8b,0xdf,0x28,0x00,0xe7,0x04,0xe3,
+                0xff},
+               {0x00,0x01,0x02,0x03,0x04,0x05,0x14,0x07,
+                0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+                0x01,0x00,0x0f,0x00},
+               {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+                0xff}
+       },
+       /* ExtVGATable */
+       {
+               0x2f,
+               {0x01,0x0f,0x00,0x0e},
+               {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+                0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+                0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+                0xff},
+               {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+                0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+                0x01,0x00,0x00,0x00},
+               {0x00,0x00,0x00,0x00,0x00,0x40,0x05,0x0f,
+                0xff}
+       },
+       /* ExtHiCTable */
+       {
+               0x2f,
+               {0x01,0x0f,0x00,0x0e},
+               {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+                0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+                0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+                0xff},
+               {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+                0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+                0x01,0x00,0x00,0x00},
+               {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+                0xff}
+       },
+       /* ExtTrueCTable */
+       {
+               0x2f,
+               {0x01,0x0f,0x00,0x0e},
+               {0x5f,0x4f,0x50,0x82,0x54,0x80,0x0b,0x3e,
+                0x00,0x40,0x00,0x00,0x00,0x00,0x00,0x00,
+                0xea,0x8c,0xdf,0x28,0x40,0xe7,0x04,0xa3,
+                0xff},
+               {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+                0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+                0x01,0x00,0x00,0x00},
+               {0x00,0x00,0x00,0x00,0x00,0x00,0x05,0x0f,
+                0xff}
+       },
+};
+
+static struct ast_vbios_enhtable res_640x480[] = {
+       { 800, 640, 8, 96, 525, 480, 2, 2, VCLK25_175,  /* 60Hz */
+         (SyncNN | HBorder | VBorder | Charx8Dot), 60, 1, 0x2E },
+       { 832, 640, 16, 40, 520, 480, 1, 3, VCLK31_5,   /* 72Hz */
+         (SyncNN | HBorder | VBorder | Charx8Dot), 72, 2, 0x2E  },
+       { 840, 640, 16, 64, 500, 480, 1, 3, VCLK31_5,   /* 75Hz */
+         (SyncNN | Charx8Dot) , 75, 3, 0x2E },
+       { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36,             /* 85Hz */
+         (SyncNN | Charx8Dot) , 85, 4, 0x2E },
+       { 832, 640, 56, 56, 509, 480, 1, 3, VCLK36,             /* end */
+         (SyncNN | Charx8Dot) , 0xFF, 4, 0x2E },
+};
+
+static struct ast_vbios_enhtable res_800x600[] = {
+       {1024, 800, 24, 72, 625, 600, 1, 2, VCLK36,             /* 56Hz */
+        (SyncPP | Charx8Dot), 56, 1, 0x30 },
+       {1056, 800, 40, 128, 628, 600, 1, 4, VCLK40,    /* 60Hz */
+        (SyncPP | Charx8Dot), 60, 2, 0x30 },
+       {1040, 800, 56, 120, 666, 600, 37, 6, VCLK50,   /* 72Hz */
+        (SyncPP | Charx8Dot), 72, 3, 0x30 },
+       {1056, 800, 16, 80, 625, 600, 1, 3, VCLK49_5,   /* 75Hz */
+        (SyncPP | Charx8Dot), 75, 4, 0x30 },
+       {1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25,  /* 85Hz */
+        (SyncPP | Charx8Dot), 84, 5, 0x30 },
+       {1048, 800, 32, 64, 631, 600, 1, 3, VCLK56_25,  /* end */
+        (SyncPP | Charx8Dot), 0xFF, 5, 0x30 },
+};
+
+
+static struct ast_vbios_enhtable res_1024x768[] = {
+       {1344, 1024, 24, 136, 806, 768, 3, 6, VCLK65,   /* 60Hz */
+        (SyncNN | Charx8Dot), 60, 1, 0x31 },
+       {1328, 1024, 24, 136, 806, 768, 3, 6, VCLK75,   /* 70Hz */
+        (SyncNN | Charx8Dot), 70, 2, 0x31 },
+       {1312, 1024, 16, 96, 800, 768, 1, 3, VCLK78_75, /* 75Hz */
+        (SyncPP | Charx8Dot), 75, 3, 0x31 },
+       {1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5,  /* 85Hz */
+        (SyncPP | Charx8Dot), 84, 4, 0x31 },
+       {1376, 1024, 48, 96, 808, 768, 1, 3, VCLK94_5,  /* end */
+        (SyncPP | Charx8Dot), 0xFF, 4, 0x31 },
+};
+
+static struct ast_vbios_enhtable res_1280x1024[] = {
+       {1688, 1280, 48, 112, 1066, 1024, 1, 3, VCLK108,        /* 60Hz */
+        (SyncPP | Charx8Dot), 60, 1, 0x32 },
+       {1688, 1280, 16, 144, 1066, 1024, 1, 3, VCLK135,        /* 75Hz */
+        (SyncPP | Charx8Dot), 75, 2, 0x32 },
+       {1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5,      /* 85Hz */
+        (SyncPP | Charx8Dot), 85, 3, 0x32 },
+       {1728, 1280, 64, 160, 1072, 1024, 1, 3, VCLK157_5,      /* end */
+        (SyncPP | Charx8Dot), 0xFF, 3, 0x32 },
+};
+
+static struct ast_vbios_enhtable res_1600x1200[] = {
+       {2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162,        /* 60Hz */
+        (SyncPP | Charx8Dot), 60, 1, 0x33 },
+       {2160, 1600, 64, 192, 1250, 1200, 1, 3, VCLK162,        /* end */
+        (SyncPP | Charx8Dot), 0xFF, 1, 0x33 },
+};
+
+static struct ast_vbios_enhtable res_1920x1200[] = {
+       {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
+        (SyncNP | Charx8Dot), 60, 1, 0x34 },
+       {2080, 1920, 48, 32, 1235, 1200, 3, 6, VCLK154, /* 60Hz */
+        (SyncNP | Charx8Dot), 0xFF, 1, 0x34 },
+};
+
+/* 16:10 */
+static struct ast_vbios_enhtable res_1280x800[] = {
+       {1680, 1280, 72,128,  831,  800, 3, 6, VCLK83_5,        /* 60Hz */
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x35 },
+       {1680, 1280, 72,128,  831,  800, 3, 6, VCLK83_5,        /* 60Hz */
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x35 },
+
+};
+
+static struct ast_vbios_enhtable res_1440x900[] = {
+       {1904, 1440, 80,152,  934,  900, 3, 6, VCLK106_5,       /* 60Hz */
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x36 },
+       {1904, 1440, 80,152,  934,  900, 3, 6, VCLK106_5,       /* 60Hz */
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x36 },
+};
+
+static struct ast_vbios_enhtable res_1680x1050[] = {
+       {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25,      /* 60Hz */
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x37 },
+       {2240, 1680,104,176, 1089, 1050, 3, 6, VCLK146_25,      /* 60Hz */
+        (SyncPN | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x37 },
+};
+
+/* HDTV */
+static struct ast_vbios_enhtable res_1920x1080[] = {
+       {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5,       /* 60Hz */
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode), 60, 1, 0x38 },
+       {2200, 1920, 88, 44, 1125, 1080, 4, 5, VCLK148_5,       /* 60Hz */
+        (SyncNP | Charx8Dot | LineCompareOff | WideScreenMode), 0xFF, 1, 0x38 },
+};
+#endif
 
--- /dev/null
+/*
+ * 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 "drmP.h"
+#include "ast_drv.h"
+#include <ttm/ttm_page_alloc.h>
+
+static inline struct ast_private *
+ast_bdev(struct ttm_bo_device *bd)
+{
+       return container_of(bd, struct ast_private, ttm.bdev);
+}
+
+static int
+ast_ttm_mem_global_init(struct drm_global_reference *ref)
+{
+       return ttm_mem_global_init(ref->object);
+}
+
+static void
+ast_ttm_mem_global_release(struct drm_global_reference *ref)
+{
+       ttm_mem_global_release(ref->object);
+}
+
+static int ast_ttm_global_init(struct ast_private *ast)
+{
+       struct drm_global_reference *global_ref;
+       int r;
+
+       global_ref = &ast->ttm.mem_global_ref;
+       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
+       global_ref->size = sizeof(struct ttm_mem_global);
+       global_ref->init = &ast_ttm_mem_global_init;
+       global_ref->release = &ast_ttm_mem_global_release;
+       r = drm_global_item_ref(global_ref);
+       if (r != 0) {
+               DRM_ERROR("Failed setting up TTM memory accounting "
+                         "subsystem.\n");
+               return r;
+       }
+
+       ast->ttm.bo_global_ref.mem_glob =
+               ast->ttm.mem_global_ref.object;
+       global_ref = &ast->ttm.bo_global_ref.ref;
+       global_ref->global_type = DRM_GLOBAL_TTM_BO;
+       global_ref->size = sizeof(struct ttm_bo_global);
+       global_ref->init = &ttm_bo_global_init;
+       global_ref->release = &ttm_bo_global_release;
+       r = drm_global_item_ref(global_ref);
+       if (r != 0) {
+               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
+               drm_global_item_unref(&ast->ttm.mem_global_ref);
+               return r;
+       }
+       return 0;
+}
+
+void
+ast_ttm_global_release(struct ast_private *ast)
+{
+       if (ast->ttm.mem_global_ref.release == NULL)
+               return;
+
+       drm_global_item_unref(&ast->ttm.bo_global_ref.ref);
+       drm_global_item_unref(&ast->ttm.mem_global_ref);
+       ast->ttm.mem_global_ref.release = NULL;
+}
+
+
+static void ast_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+       struct ast_bo *bo;
+
+       bo = container_of(tbo, struct ast_bo, bo);
+
+       drm_gem_object_release(&bo->gem);
+       kfree(bo);
+}
+
+bool ast_ttm_bo_is_ast_bo(struct ttm_buffer_object *bo)
+{
+       if (bo->destroy == &ast_bo_ttm_destroy)
+               return true;
+       return false;
+}
+
+static int
+ast_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+                    struct ttm_mem_type_manager *man)
+{
+       switch (type) {
+       case TTM_PL_SYSTEM:
+               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+               man->available_caching = TTM_PL_MASK_CACHING;
+               man->default_caching = TTM_PL_FLAG_CACHED;
+               break;
+       case TTM_PL_VRAM:
+               man->func = &ttm_bo_manager_func;
+               man->flags = TTM_MEMTYPE_FLAG_FIXED |
+                       TTM_MEMTYPE_FLAG_MAPPABLE;
+               man->available_caching = TTM_PL_FLAG_UNCACHED |
+                       TTM_PL_FLAG_WC;
+               man->default_caching = TTM_PL_FLAG_WC;
+               break;
+       default:
+               DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void
+ast_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+{
+       struct ast_bo *astbo = ast_bo(bo);
+
+       if (!ast_ttm_bo_is_ast_bo(bo))
+               return;
+
+       ast_ttm_placement(astbo, TTM_PL_FLAG_SYSTEM);
+       *pl = astbo->placement;
+}
+
+static int ast_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
+{
+       return 0;
+}
+
+static int ast_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
+                                 struct ttm_mem_reg *mem)
+{
+       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+       struct ast_private *ast = ast_bdev(bdev);
+
+       mem->bus.addr = NULL;
+       mem->bus.offset = 0;
+       mem->bus.size = mem->num_pages << PAGE_SHIFT;
+       mem->bus.base = 0;
+       mem->bus.is_iomem = false;
+       if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+               return -EINVAL;
+       switch (mem->mem_type) {
+       case TTM_PL_SYSTEM:
+               /* system memory */
+               return 0;
+       case TTM_PL_VRAM:
+               mem->bus.offset = mem->start << PAGE_SHIFT;
+               mem->bus.base = pci_resource_start(ast->dev->pdev, 0);
+               mem->bus.is_iomem = true;
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+       return 0;
+}
+
+static void ast_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
+{
+}
+
+static int ast_bo_move(struct ttm_buffer_object *bo,
+                      bool evict, bool interruptible,
+                      bool no_wait_reserve, bool no_wait_gpu,
+                      struct ttm_mem_reg *new_mem)
+{
+       int r;
+       r = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem);
+       return r;
+}
+
+
+static void ast_ttm_backend_destroy(struct ttm_tt *tt)
+{
+       ttm_tt_fini(tt);
+       kfree(tt);
+}
+
+static struct ttm_backend_func ast_tt_backend_func = {
+       .destroy = &ast_ttm_backend_destroy,
+};
+
+
+struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev,
+                                unsigned long size, uint32_t page_flags,
+                                struct page *dummy_read_page)
+{
+       struct ttm_tt *tt;
+
+       tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL);
+       if (tt == NULL)
+               return NULL;
+       tt->func = &ast_tt_backend_func;
+       if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
+               kfree(tt);
+               return NULL;
+       }
+       return tt;
+}
+
+static int ast_ttm_tt_populate(struct ttm_tt *ttm)
+{
+       return ttm_pool_populate(ttm);
+}
+
+static void ast_ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+       ttm_pool_unpopulate(ttm);
+}
+
+struct ttm_bo_driver ast_bo_driver = {
+       .ttm_tt_create = ast_ttm_tt_create,
+       .ttm_tt_populate = ast_ttm_tt_populate,
+       .ttm_tt_unpopulate = ast_ttm_tt_unpopulate,
+       .init_mem_type = ast_bo_init_mem_type,
+       .evict_flags = ast_bo_evict_flags,
+       .move = ast_bo_move,
+       .verify_access = ast_bo_verify_access,
+       .io_mem_reserve = &ast_ttm_io_mem_reserve,
+       .io_mem_free = &ast_ttm_io_mem_free,
+};
+
+int ast_mm_init(struct ast_private *ast)
+{
+       int ret;
+       struct drm_device *dev = ast->dev;
+       struct ttm_bo_device *bdev = &ast->ttm.bdev;
+
+       ret = ast_ttm_global_init(ast);
+       if (ret)
+               return ret;
+
+       ret = ttm_bo_device_init(&ast->ttm.bdev,
+                                ast->ttm.bo_global_ref.ref.object,
+                                &ast_bo_driver, DRM_FILE_PAGE_OFFSET,
+                                true);
+       if (ret) {
+               DRM_ERROR("Error initialising bo driver; %d\n", ret);
+               return ret;
+       }
+
+       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
+                            ast->vram_size >> PAGE_SHIFT);
+       if (ret) {
+               DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
+               return ret;
+       }
+
+       ast->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 0),
+                                   pci_resource_len(dev->pdev, 0),
+                                   DRM_MTRR_WC);
+
+       return 0;
+}
+
+void ast_mm_fini(struct ast_private *ast)
+{
+       struct drm_device *dev = ast->dev;
+       ttm_bo_device_release(&ast->ttm.bdev);
+
+       ast_ttm_global_release(ast);
+
+       if (ast->fb_mtrr >= 0) {
+               drm_mtrr_del(ast->fb_mtrr,
+                            pci_resource_start(dev->pdev, 0),
+                            pci_resource_len(dev->pdev, 0), DRM_MTRR_WC);
+               ast->fb_mtrr = -1;
+       }
+}
+
+void ast_ttm_placement(struct ast_bo *bo, int domain)
+{
+       u32 c = 0;
+       bo->placement.fpfn = 0;
+       bo->placement.lpfn = 0;
+       bo->placement.placement = bo->placements;
+       bo->placement.busy_placement = bo->placements;
+       if (domain & TTM_PL_FLAG_VRAM)
+               bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_VRAM;
+       if (domain & TTM_PL_FLAG_SYSTEM)
+               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+       if (!c)
+               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+       bo->placement.num_placement = c;
+       bo->placement.num_busy_placement = c;
+}
+
+int ast_bo_reserve(struct ast_bo *bo, bool no_wait)
+{
+       int ret;
+
+       ret = ttm_bo_reserve(&bo->bo, true, no_wait, false, 0);
+       if (ret) {
+               if (ret != -ERESTARTSYS)
+                       DRM_ERROR("reserve failed %p\n", bo);
+               return ret;
+       }
+       return 0;
+}
+
+void ast_bo_unreserve(struct ast_bo *bo)
+{
+       ttm_bo_unreserve(&bo->bo);
+}
+
+int ast_bo_create(struct drm_device *dev, int size, int align,
+                 uint32_t flags, struct ast_bo **pastbo)
+{
+       struct ast_private *ast = dev->dev_private;
+       struct ast_bo *astbo;
+       size_t acc_size;
+       int ret;
+
+       astbo = kzalloc(sizeof(struct ast_bo), GFP_KERNEL);
+       if (!astbo)
+               return -ENOMEM;
+
+       ret = drm_gem_object_init(dev, &astbo->gem, size);
+       if (ret) {
+               kfree(astbo);
+               return ret;
+       }
+
+       astbo->gem.driver_private = NULL;
+       astbo->bo.bdev = &ast->ttm.bdev;
+
+       ast_ttm_placement(astbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+       acc_size = ttm_bo_dma_acc_size(&ast->ttm.bdev, size,
+                                      sizeof(struct ast_bo));
+
+       ret = ttm_bo_init(&ast->ttm.bdev, &astbo->bo, size,
+                         ttm_bo_type_device, &astbo->placement,
+                         align >> PAGE_SHIFT, 0, false, NULL, acc_size,
+                         ast_bo_ttm_destroy);
+       if (ret)
+               return ret;
+
+       *pastbo = astbo;
+       return 0;
+}
+
+static inline u64 ast_bo_gpu_offset(struct ast_bo *bo)
+{
+       return bo->bo.offset;
+}
+
+int ast_bo_pin(struct ast_bo *bo, u32 pl_flag, u64 *gpu_addr)
+{
+       int i, ret;
+
+       if (bo->pin_count) {
+               bo->pin_count++;
+               if (gpu_addr)
+                       *gpu_addr = ast_bo_gpu_offset(bo);
+       }
+
+       ast_ttm_placement(bo, pl_flag);
+       for (i = 0; i < bo->placement.num_placement; i++)
+               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+       if (ret)
+               return ret;
+
+       bo->pin_count = 1;
+       if (gpu_addr)
+               *gpu_addr = ast_bo_gpu_offset(bo);
+       return 0;
+}
+
+int ast_bo_unpin(struct ast_bo *bo)
+{
+       int i, ret;
+       if (!bo->pin_count) {
+               DRM_ERROR("unpin bad %p\n", bo);
+               return 0;
+       }
+       bo->pin_count--;
+       if (bo->pin_count)
+               return 0;
+
+       for (i = 0; i < bo->placement.num_placement ; i++)
+               bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT;
+       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int ast_bo_push_sysram(struct ast_bo *bo)
+{
+       int i, ret;
+       if (!bo->pin_count) {
+               DRM_ERROR("unpin bad %p\n", bo);
+               return 0;
+       }
+       bo->pin_count--;
+       if (bo->pin_count)
+               return 0;
+
+       if (bo->kmap.virtual)
+               ttm_bo_kunmap(&bo->kmap);
+
+       ast_ttm_placement(bo, TTM_PL_FLAG_SYSTEM);
+       for (i = 0; i < bo->placement.num_placement ; i++)
+               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+
+       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false, false);
+       if (ret) {
+               DRM_ERROR("pushing to VRAM failed\n");
+               return ret;
+       }
+       return 0;
+}
+
+int ast_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_file *file_priv;
+       struct ast_private *ast;
+
+       if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+               return drm_mmap(filp, vma);
+
+       file_priv = filp->private_data;
+       ast = file_priv->minor->dev->dev_private;
+       return ttm_bo_mmap(filp, vma, &ast->ttm.bdev);
+}