The plan here is to slowly get X out of the hardware initialization business. Anything that is playing with registers from user space needs to be migrated into the drivers. Another factor is the desire to slowly get X into a position where it doesn't need to run as root. As long as X plays with the registers from user space it has to stay a root priv app.
X on GL runs on top of mesa-solo. Since X on GL doesn't use the 2D DDXs the hardware initialization has to come from somewhere else. Things needing root priv need to go into the driver. But there is nothing stopping you from computing register values in user space and then passing them into a small IOCTL. The user space code for the IOCTL is in mesa-solo. The goal is to end up with a controlling X app running non-root which then authorizes non-root clients. While we are in transition initialization code needs to go into the DDX and mesa-solo driver/server directories. It going to take a while to convert everything over. The process will probably be different for each card. On Fri, 17 Sep 2004 00:20:04 +0200, Felix Kühling <[EMAIL PROTECTED]> wrote: > Hi Jon, > > I'm going to start writing the code for permanent maps in the Savage > driver now. I'm becoming aware of the practical problems now and I'd > like to know if my understanding is correct so far. > > The first problem I have is that I need to find out the size of the > video memory in order to create the framebuffer map correctly. Since > permanent maps are supposed to be created when the driver is loaded in > the preinit or postinit hooks, X can't provide that information in the > init ioctl. So I'll have to copy some pretty magic (to me at least) code This is what I'm trying to get rid of. X shouldn't be telling a device driver what hardware it has, it should be the other way around. > from the DDX to the kernel driver in order to do the hardware and video > memory detection. The code in the Savage DDX uses MMIO register access > in order to find out the amount of video ram. This means I'll have to > enable MMIO in the kernel driver now. I hope that won't interfere with we had to do that for the radeon too > the DDX driver that probably expects MMIO to be disabled when it is > first loaded. > > I havn't found any example of a driver using permanent maps in the > current DRM sources. You referred to the radeon driver sometimes, but > the only thing I could find was a comment above radeon_preinit. Grep > doesn't find any call to initmap in any of the drivers. Is this > something you forgot to commit? I'd really like to take a look at an > example, since this is the first time I'm working with a DRM driver. The small attached file uses the maps and enables MMIO in the radeon driver. > > Regards, > Felix > > | Felix Kühling <[EMAIL PROTECTED]> http://fxk.de.vu | > | PGP Fingerprint: 6A3C 9566 5B30 DDED 73C3 B152 151C 5CC1 D888 E595 | > -- Jon Smirl [EMAIL PROTECTED]
diff -Nru a/linux/Makefile.kernel b/linux/Makefile.kernel --- a/linux/Makefile.kernel Sun Sep 12 02:27:43 2004 +++ b/linux/Makefile.kernel Sun Sep 12 02:27:43 2004 @@ -13,7 +13,7 @@ i810-objs := i810_drv.o i810_dma.o i830-objs := i830_drv.o i830_dma.o i830_irq.o i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o -radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o +radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o radeon_i2c.o sis-objs := sis_drv.o sis_ds.o sis_mm.o ffb-objs := ffb_drv.o ffb_context.o savage-objs := savage_drv.o savage_dma.o diff -Nru a/linux/radeon_gpl.h b/linux/radeon_gpl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/linux/radeon_gpl.h Sun Sep 12 02:27:43 2004 @@ -0,0 +1,29 @@ +/* + * linux/radeon_gpl.h + * + * Original author probably Benjamin Herrenschmidt <[EMAIL PROTECTED]> + * or Kronos <[EMAIL PROTECTED]> + * Based on Xfree sources + * (C) Copyright 2004 Jon Smirl <[EMAIL PROTECTED]> + * + * This is a GPL licensed file from the Linux kernel, don't add it to the BSD build + * + * Radeon I2C support routines + * + */ + +#include <linux/i2c.h> +#include <linux/i2c-id.h> +#include <linux/i2c-algo-bit.h> + +struct radeon_i2c_chan { + drm_device_t *dev; + u32 ddc_reg; + struct i2c_adapter adapter; + struct i2c_algo_bit_data algo; +}; + +extern int radeon_create_i2c_busses(drm_device_t *dev); +extern void radeon_delete_i2c_busses(drm_device_t *dev); + + diff -Nru a/linux/radeon_i2c.c b/linux/radeon_i2c.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/linux/radeon_i2c.c Sun Sep 12 02:27:43 2004 @@ -0,0 +1,152 @@ +/* + * linux/radeon_i2c.c + * + * Original author probably Benjamin Herrenschmidt <[EMAIL PROTECTED]> + * or Kronos <[EMAIL PROTECTED]> + * Based on Xfree sources + * (C) Copyright 2004 Jon Smirl <[EMAIL PROTECTED]> + * + * This is a GPL licensed file from the Linux kernel, don't add it to the BSD build + * + * Radeon I2C support routines + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/fb.h> + +#include <asm/io.h> +#include <video/radeon.h> + +#include "radeon.h" +#include "drmP.h" +#include "drm.h" +#include "radeon_drm.h" +#include "radeon_drv.h" + +static void gpio_setscl(void* data, int state) +{ + struct radeon_i2c_chan *chan = data; + drm_radeon_private_t *dev_priv = chan->dev->dev_private; + u32 val; + + val = RADEON_READ(chan->ddc_reg) & ~(VGA_DDC_CLK_OUT_EN); + if (!state) + val |= VGA_DDC_CLK_OUT_EN; + + RADEON_WRITE(chan->ddc_reg, val); + (void)RADEON_READ(chan->ddc_reg); +} + +static void gpio_setsda(void* data, int state) +{ + struct radeon_i2c_chan *chan = data; + drm_radeon_private_t *dev_priv = chan->dev->dev_private; + u32 val; + + val = RADEON_READ(chan->ddc_reg) & ~(VGA_DDC_DATA_OUT_EN); + if (!state) + val |= VGA_DDC_DATA_OUT_EN; + + RADEON_WRITE(chan->ddc_reg, val); + (void)RADEON_READ(chan->ddc_reg); +} + +static int gpio_getscl(void* data) +{ + struct radeon_i2c_chan *chan = data; + drm_radeon_private_t *dev_priv = chan->dev->dev_private; + u32 val; + + val = RADEON_READ(chan->ddc_reg); + + return (val & VGA_DDC_CLK_INPUT) ? 1 : 0; +} + +static int gpio_getsda(void* data) +{ + struct radeon_i2c_chan *chan = data; + drm_radeon_private_t *dev_priv = chan->dev->dev_private; + u32 val; + + val = RADEON_READ(chan->ddc_reg); + + return (val & VGA_DDC_DATA_INPUT) ? 1 : 0; +} + +static int setup_i2c_bus(struct radeon_i2c_chan *chan, const char *name) +{ + int rc; + + strcpy(chan->adapter.name, name); + chan->adapter.owner = THIS_MODULE; + chan->adapter.id = I2C_ALGO_ATI; + chan->adapter.algo_data = &chan->algo; + chan->adapter.dev.parent = &chan->dev->pdev->dev; + chan->algo.setsda = gpio_setsda; + chan->algo.setscl = gpio_setscl; + chan->algo.getsda = gpio_getsda; + chan->algo.getscl = gpio_getscl; + chan->algo.udelay = 40; + chan->algo.timeout = 20; + chan->algo.data = chan; + + i2c_set_adapdata(&chan->adapter, chan); + + /* Raise SCL and SDA */ + gpio_setsda(chan, 1); + gpio_setscl(chan, 1); + udelay(20); + + rc = i2c_bit_add_bus(&chan->adapter); + if (rc == 0) + DRM_DEBUG("I2C bus %s registered.\n", name); + else + DRM_ERROR("Failed to register I2C bus %s.\n", name); + return rc; +} + +int radeon_create_i2c_busses(drm_device_t *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int ret; + + dev_priv->i2c[0].dev = dev; + dev_priv->i2c[0].ddc_reg = GPIO_MONID; + if ((ret = setup_i2c_bus(&dev_priv->i2c[0], "monid"))) + return ret; + + dev_priv->i2c[1].dev = dev; + dev_priv->i2c[1].ddc_reg = GPIO_DVI_DDC; + if ((ret = setup_i2c_bus(&dev_priv->i2c[1], "dvi"))) + return ret; + + dev_priv->i2c[2].dev = dev; + dev_priv->i2c[2].ddc_reg = GPIO_VGA_DDC; + if ((ret = setup_i2c_bus(&dev_priv->i2c[2], "vga"))) + return ret; + + dev_priv->i2c[3].dev = dev; + dev_priv->i2c[3].ddc_reg = GPIO_CRT2_DDC; + if ((ret = setup_i2c_bus(&dev_priv->i2c[3], "crt2"))) + return ret; + return 0; +} + +void radeon_delete_i2c_busses(drm_device_t *dev) +{ + drm_radeon_private_t *dev_priv = dev->dev_private; + int i, ret; + + for (i = 0; i < 4; i++) { + if (dev_priv->i2c[i].dev) { + ret = i2c_bit_del_bus(&dev_priv->i2c[i].adapter); + } + dev_priv->i2c[i].dev = NULL; + } +} diff -Nru a/shared/radeon_cp.c b/shared/radeon_cp.c --- a/shared/radeon_cp.c Sun Sep 12 02:27:43 2004 +++ b/shared/radeon_cp.c Sun Sep 12 02:27:43 2004 @@ -36,7 +36,6 @@ #define RADEON_FIFO_DEBUG 0 - /* CP microcode (from ATI) */ static u32 R200_cp_microcode[][2] = { { 0x21007000, 0000000000 }, @@ -1285,12 +1284,8 @@ dev_priv->bus_pci_gart )) DRM_ERROR( "failed to cleanup PCI GART!\n" ); } - - { - int flags = dev_priv->flags; - memset(dev_priv, 0, sizeof(*dev_priv)); - dev_priv->flags = flags; - } + /* only clear to the start of flags */ + memset(dev_priv, 0, offsetof(drm_radeon_private_t, flags)); return 0; } @@ -1735,8 +1730,9 @@ /* Always create a map record for MMIO and FB memory, done from DRIVER_POSTINIT */ int radeon_preinit( struct drm_device *dev, unsigned long flags ) { - u32 save, temp; + u32 save, temp, memmode; drm_radeon_private_t *dev_priv; + int ret = 0; dev_priv = DRM(alloc)( sizeof(drm_radeon_private_t), DRM_MEM_DRIVER ); if ( dev_priv == NULL ) @@ -1746,6 +1742,17 @@ dev->dev_private = (void *)dev_priv; dev_priv->flags = flags; + /* registers */ + /* PCI space is twice the real size, so that you can have a RW and RO mapping */ + if( (ret = DRM(initmap)( dev, pci_resource_start( dev->pdev, 2 ), + pci_resource_len( dev->pdev, 2 ) / 2, _DRM_REGISTERS, 0 ))) + return ret; + + /* framebuffer */ + if( (ret = DRM(initmap)( dev, pci_resource_start( dev->pdev, 0 ), + pci_resource_len( dev->pdev, 0 ), _DRM_FRAME_BUFFER, _DRM_WRITE_COMBINING ))) + return ret; + /* There are signatures in BIOS and PCI-SSID for a PCI card, but they are not very reliable. Following detection method works for all cards tested so far. Note, checking AGP_ENABLE bit after drmAgpEnable call can also give the correct result. @@ -1759,8 +1766,19 @@ dev_priv->flags |= CHIP_IS_AGP; DRM_DEBUG("%s card detected\n", ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : "PCI")); pci_write_config_dword(dev->pdev, RADEON_AGP_COMMAND_PCI_CONFIG, save); + + /* Check if we need a reset */ + if (!(dev_priv->mmio = drm_core_findmap(dev , pci_resource_start( dev->pdev, 2 )))) + return DRM_ERR(ENOMEM); - return 0; + memmode = RADEON_READ(RADEON_MEM_SDRAM_MODE_REG); + DRM_DEBUG("Memmode is %x, if zero needs reset\n", memmode); + dev->need_reset = (memmode == 0); + +#if defined(__linux__) + ret = radeon_create_i2c_busses(dev); +#endif + return ret; } int radeon_postinit( struct drm_device *dev, unsigned long flags ) @@ -1772,6 +1790,10 @@ { drm_radeon_private_t *dev_priv = dev->dev_private; + DRM_DEBUG("\n"); +#if defined(__linux__) + radeon_delete_i2c_busses(dev); +#endif DRM(free)( dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER ); dev->dev_private = NULL; diff -Nru a/shared/radeon_drv.h b/shared/radeon_drv.h --- a/shared/radeon_drv.h Sun Sep 12 02:27:43 2004 +++ b/shared/radeon_drv.h Sun Sep 12 02:27:43 2004 @@ -31,6 +31,10 @@ #ifndef __RADEON_DRV_H__ #define __RADEON_DRV_H__ +#if defined(__linux__) +#include "radeon_gpl.h" +#endif + /* * Chip flags */ @@ -86,8 +90,6 @@ typedef struct drm_radeon_private { - uint32_t flags; /* see radeon_chip_flags */ - drm_radeon_ring_buffer_t ring; drm_radeon_sarea_t *sarea_priv; @@ -164,6 +166,11 @@ wait_queue_head_t swi_queue; atomic_t swi_emitted; + /* starting from here on, data is preserved accross an open */ + uint32_t flags; /* see radeon_chip_flags */ +#if defined(__linux__) + struct radeon_i2c_chan i2c[4]; +#endif } drm_radeon_private_t; typedef struct drm_radeon_buf_priv {