// SPDX-License-Identifier: GPL-2.0 or MIT1/*2* Copyright 2018 Noralf Trønnes3*/45#include <linux/export.h>6#include <linux/iosys-map.h>7#include <linux/list.h>8#include <linux/mutex.h>9#include <linux/seq_file.h>10#include <linux/slab.h>1112#include <drm/drm_client.h>13#include <drm/drm_client_event.h>14#include <drm/drm_device.h>15#include <drm/drm_drv.h>16#include <drm/drm_file.h>17#include <drm/drm_fourcc.h>18#include <drm/drm_framebuffer.h>19#include <drm/drm_gem.h>20#include <drm/drm_gem_framebuffer_helper.h>21#include <drm/drm_mode.h>22#include <drm/drm_print.h>2324#include "drm_crtc_internal.h"25#include "drm_internal.h"2627/**28* DOC: overview29*30* This library provides support for clients running in the kernel like fbdev and bootsplash.31*32* GEM drivers which provide a GEM based dumb buffer with a virtual address are supported.33*/3435static int drm_client_open(struct drm_client_dev *client)36{37struct drm_device *dev = client->dev;38struct drm_file *file;3940file = drm_file_alloc(dev->primary);41if (IS_ERR(file))42return PTR_ERR(file);4344mutex_lock(&dev->filelist_mutex);45list_add(&file->lhead, &dev->filelist_internal);46mutex_unlock(&dev->filelist_mutex);4748client->file = file;4950return 0;51}5253static void drm_client_close(struct drm_client_dev *client)54{55struct drm_device *dev = client->dev;5657mutex_lock(&dev->filelist_mutex);58list_del(&client->file->lhead);59mutex_unlock(&dev->filelist_mutex);6061drm_file_free(client->file);62}6364/**65* drm_client_init - Initialise a DRM client66* @dev: DRM device67* @client: DRM client68* @name: Client name69* @funcs: DRM client functions (optional)70*71* This initialises the client and opens a &drm_file.72* Use drm_client_register() to complete the process.73* The caller needs to hold a reference on @dev before calling this function.74* The client is freed when the &drm_device is unregistered. See drm_client_release().75*76* Returns:77* Zero on success or negative error code on failure.78*/79int drm_client_init(struct drm_device *dev, struct drm_client_dev *client,80const char *name, const struct drm_client_funcs *funcs)81{82int ret;8384if (!drm_core_check_feature(dev, DRIVER_MODESET) || !dev->driver->dumb_create)85return -EOPNOTSUPP;8687client->dev = dev;88client->name = name;89client->funcs = funcs;9091ret = drm_client_modeset_create(client);92if (ret)93return ret;9495ret = drm_client_open(client);96if (ret)97goto err_free;9899drm_dev_get(dev);100101return 0;102103err_free:104drm_client_modeset_free(client);105return ret;106}107EXPORT_SYMBOL(drm_client_init);108109/**110* drm_client_register - Register client111* @client: DRM client112*113* Add the client to the &drm_device client list to activate its callbacks.114* @client must be initialized by a call to drm_client_init(). After115* drm_client_register() it is no longer permissible to call drm_client_release()116* directly (outside the unregister callback), instead cleanup will happen117* automatically on driver unload.118*119* Registering a client generates a hotplug event that allows the client120* to set up its display from pre-existing outputs. The client must have121* initialized its state to able to handle the hotplug event successfully.122*/123void drm_client_register(struct drm_client_dev *client)124{125struct drm_device *dev = client->dev;126int ret;127128mutex_lock(&dev->clientlist_mutex);129list_add(&client->list, &dev->clientlist);130131if (client->funcs && client->funcs->hotplug) {132/*133* Perform an initial hotplug event to pick up the134* display configuration for the client. This step135* has to be performed *after* registering the client136* in the list of clients, or a concurrent hotplug137* event might be lost; leaving the display off.138*139* Hold the clientlist_mutex as for a regular hotplug140* event.141*/142ret = client->funcs->hotplug(client);143if (ret)144drm_dbg_kms(dev, "client hotplug ret=%d\n", ret);145}146mutex_unlock(&dev->clientlist_mutex);147}148EXPORT_SYMBOL(drm_client_register);149150/**151* drm_client_release - Release DRM client resources152* @client: DRM client153*154* Releases resources by closing the &drm_file that was opened by drm_client_init().155* It is called automatically if the &drm_client_funcs.unregister callback is _not_ set.156*157* This function should only be called from the unregister callback. An exception158* is fbdev which cannot free the buffer if userspace has open file descriptors.159*160* Note:161* Clients cannot initiate a release by themselves. This is done to keep the code simple.162* The driver has to be unloaded before the client can be unloaded.163*/164void drm_client_release(struct drm_client_dev *client)165{166struct drm_device *dev = client->dev;167168drm_dbg_kms(dev, "%s\n", client->name);169170drm_client_modeset_free(client);171drm_client_close(client);172173if (client->funcs && client->funcs->free)174client->funcs->free(client);175176drm_dev_put(dev);177}178EXPORT_SYMBOL(drm_client_release);179180/**181* drm_client_buffer_delete - Delete a client buffer182* @buffer: DRM client buffer183*/184void drm_client_buffer_delete(struct drm_client_buffer *buffer)185{186struct drm_gem_object *gem;187int ret;188189if (!buffer)190return;191192gem = buffer->fb->obj[0];193drm_gem_vunmap(gem, &buffer->map);194195ret = drm_mode_rmfb(buffer->client->dev, buffer->fb->base.id, buffer->client->file);196if (ret)197drm_err(buffer->client->dev,198"Error removing FB:%u (%d)\n", buffer->fb->base.id, ret);199200drm_gem_object_put(buffer->gem);201202kfree(buffer);203}204EXPORT_SYMBOL(drm_client_buffer_delete);205206static struct drm_client_buffer *207drm_client_buffer_create(struct drm_client_dev *client, u32 width, u32 height,208u32 format, u32 handle, u32 pitch)209{210struct drm_mode_fb_cmd2 fb_req = {211.width = width,212.height = height,213.pixel_format = format,214.handles = {215handle,216},217.pitches = {218pitch,219},220};221struct drm_device *dev = client->dev;222struct drm_client_buffer *buffer;223struct drm_gem_object *obj;224struct drm_framebuffer *fb;225int ret;226227buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);228if (!buffer)229return ERR_PTR(-ENOMEM);230231buffer->client = client;232233obj = drm_gem_object_lookup(client->file, handle);234if (!obj) {235ret = -ENOENT;236goto err_delete;237}238239ret = drm_mode_addfb2(dev, &fb_req, client->file);240if (ret)241goto err_drm_gem_object_put;242243fb = drm_framebuffer_lookup(dev, client->file, fb_req.fb_id);244if (drm_WARN_ON(dev, !fb)) {245ret = -ENOENT;246goto err_drm_mode_rmfb;247}248249/* drop the reference we picked up in framebuffer lookup */250drm_framebuffer_put(fb);251252strscpy(fb->comm, client->name, TASK_COMM_LEN);253254buffer->gem = obj;255buffer->fb = fb;256257return buffer;258259err_drm_mode_rmfb:260drm_mode_rmfb(dev, fb_req.fb_id, client->file);261err_drm_gem_object_put:262drm_gem_object_put(obj);263err_delete:264kfree(buffer);265return ERR_PTR(ret);266}267268/**269* drm_client_buffer_vmap_local - Map DRM client buffer into address space270* @buffer: DRM client buffer271* @map_copy: Returns the mapped memory's address272*273* This function maps a client buffer into kernel address space. If the274* buffer is already mapped, it returns the existing mapping's address.275*276* Client buffer mappings are not ref'counted. Each call to277* drm_client_buffer_vmap_local() should be closely followed by a call to278* drm_client_buffer_vunmap_local(). See drm_client_buffer_vmap() for279* long-term mappings.280*281* The returned address is a copy of the internal value. In contrast to282* other vmap interfaces, you don't need it for the client's vunmap283* function. So you can modify it at will during blit and draw operations.284*285* Returns:286* 0 on success, or a negative errno code otherwise.287*/288int drm_client_buffer_vmap_local(struct drm_client_buffer *buffer,289struct iosys_map *map_copy)290{291struct drm_gem_object *gem = buffer->fb->obj[0];292struct iosys_map *map = &buffer->map;293int ret;294295drm_gem_lock(gem);296297ret = drm_gem_vmap_locked(gem, map);298if (ret)299goto err_drm_gem_vmap_unlocked;300*map_copy = *map;301302return 0;303304err_drm_gem_vmap_unlocked:305drm_gem_unlock(gem);306return ret;307}308EXPORT_SYMBOL(drm_client_buffer_vmap_local);309310/**311* drm_client_buffer_vunmap_local - Unmap DRM client buffer312* @buffer: DRM client buffer313*314* This function removes a client buffer's memory mapping established315* with drm_client_buffer_vunmap_local(). Calling this function is only316* required by clients that manage their buffer mappings by themselves.317*/318void drm_client_buffer_vunmap_local(struct drm_client_buffer *buffer)319{320struct drm_gem_object *gem = buffer->fb->obj[0];321struct iosys_map *map = &buffer->map;322323drm_gem_vunmap_locked(gem, map);324drm_gem_unlock(gem);325}326EXPORT_SYMBOL(drm_client_buffer_vunmap_local);327328/**329* drm_client_buffer_vmap - Map DRM client buffer into address space330* @buffer: DRM client buffer331* @map_copy: Returns the mapped memory's address332*333* This function maps a client buffer into kernel address space. If the334* buffer is already mapped, it returns the existing mapping's address.335*336* Client buffer mappings are not ref'counted. Each call to337* drm_client_buffer_vmap() should be followed by a call to338* drm_client_buffer_vunmap(); or the client buffer should be mapped339* throughout its lifetime.340*341* The returned address is a copy of the internal value. In contrast to342* other vmap interfaces, you don't need it for the client's vunmap343* function. So you can modify it at will during blit and draw operations.344*345* Returns:346* 0 on success, or a negative errno code otherwise.347*/348int drm_client_buffer_vmap(struct drm_client_buffer *buffer,349struct iosys_map *map_copy)350{351struct drm_gem_object *gem = buffer->fb->obj[0];352int ret;353354ret = drm_gem_vmap(gem, &buffer->map);355if (ret)356return ret;357*map_copy = buffer->map;358359return 0;360}361EXPORT_SYMBOL(drm_client_buffer_vmap);362363/**364* drm_client_buffer_vunmap - Unmap DRM client buffer365* @buffer: DRM client buffer366*367* This function removes a client buffer's memory mapping. Calling this368* function is only required by clients that manage their buffer mappings369* by themselves.370*/371void drm_client_buffer_vunmap(struct drm_client_buffer *buffer)372{373struct drm_gem_object *gem = buffer->fb->obj[0];374375drm_gem_vunmap(gem, &buffer->map);376}377EXPORT_SYMBOL(drm_client_buffer_vunmap);378379/**380* drm_client_buffer_create_dumb - Create a client buffer backed by a dumb buffer381* @client: DRM client382* @width: Framebuffer width383* @height: Framebuffer height384* @format: Buffer format385*386* This function creates a &drm_client_buffer which consists of a387* &drm_framebuffer backed by a dumb buffer.388* Call drm_client_buffer_delete() to free the buffer.389*390* Returns:391* Pointer to a client buffer or an error pointer on failure.392*/393struct drm_client_buffer *394drm_client_buffer_create_dumb(struct drm_client_dev *client, u32 width, u32 height, u32 format)395{396const struct drm_format_info *info = drm_format_info(format);397struct drm_device *dev = client->dev;398struct drm_mode_create_dumb dumb_args = { };399struct drm_client_buffer *buffer;400int ret;401402dumb_args.width = width;403dumb_args.height = height;404dumb_args.bpp = drm_format_info_bpp(info, 0);405ret = drm_mode_create_dumb(dev, &dumb_args, client->file);406if (ret)407return ERR_PTR(ret);408409buffer = drm_client_buffer_create(client, width, height, format,410dumb_args.handle, dumb_args.pitch);411if (IS_ERR(buffer)) {412ret = PTR_ERR(buffer);413goto err_drm_mode_destroy_dumb;414}415416/*417* The handle is only needed for creating the framebuffer, destroy it418* again to solve a circular dependency should anybody export the GEM419* object as DMA-buf. The framebuffer and our buffer structure are still420* holding references to the GEM object to prevent its destruction.421*/422drm_mode_destroy_dumb(client->dev, dumb_args.handle, client->file);423424return buffer;425426err_drm_mode_destroy_dumb:427drm_mode_destroy_dumb(client->dev, dumb_args.handle, client->file);428return ERR_PTR(ret);429}430EXPORT_SYMBOL(drm_client_buffer_create_dumb);431432/**433* drm_client_buffer_flush - Manually flush client buffer434* @buffer: DRM client buffer435* @rect: Damage rectangle (if NULL flushes all)436*437* This calls &drm_framebuffer_funcs->dirty (if present) to flush buffer changes438* for drivers that need it.439*440* Returns:441* Zero on success or negative error code on failure.442*/443int drm_client_buffer_flush(struct drm_client_buffer *buffer, struct drm_rect *rect)444{445if (!buffer || !buffer->fb || !buffer->fb->funcs->dirty)446return 0;447448if (rect) {449struct drm_clip_rect clip = {450.x1 = rect->x1,451.y1 = rect->y1,452.x2 = rect->x2,453.y2 = rect->y2,454};455456return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,4570, 0, &clip, 1);458}459460return buffer->fb->funcs->dirty(buffer->fb, buffer->client->file,4610, 0, NULL, 0);462}463EXPORT_SYMBOL(drm_client_buffer_flush);464465466